package org.example; import com.google.gson.Gson; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import org.junit.jupiter.api.Test; import java.io.UnsupportedEncodingException; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.PrivateKey; import java.security.PublicKey; import java.text.SimpleDateFormat; import java.util.*; /** * 票通Demo 用于参考报文组装和加密示例 * * HtppUtils :post请求用的java原生的IO.net,没有考虑超时/长连接等特殊情况.使用到真正项目时最好采用项目http框架 * * demo在json转换的时候使用了Gson,单元测试的时候使用了Junit 以下是Maven依赖有需要添加即可: * * com.google.code.gson * gson * 2.8.9 * * * * * junit * junit * 4.13.2 * test * * */ public class Demo { //私钥(与发给票通的公钥为一对) private String privateKey = "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAIVLAoolDaE7m5oMB1ZrILHkMXMF6qmC8I/FCejz4hwBcj59H3rbtcycBEmExOJTGwexFkNgRakhqM+3uP3VybWu1GBYNmqVzggWKKzThul9VPE3+OTMlxeG4H63RsCO1//J0MoUavXMMkL3txkZBO5EtTqek182eePOV8fC3ZxpAgMBAAECgYBp4Gg3BTGrZaa2mWFmspd41lK1E/kPBrRA7vltMfPj3P47RrYvp7/js/Xv0+d0AyFQXcjaYelTbCokPMJT1nJumb2A/Cqy3yGKX3Z6QibvByBlCKK29lZkw8WVRGFIzCIXhGKdqukXf8RyqfhInqHpZ9AoY2W60bbSP6EXj/rhNQJBAL76SmpQOrnCI8Xu75di0eXBN/bE9tKsf7AgMkpFRhaU8VLbvd27U9vRWqtu67RY3sOeRMh38JZBwAIS8tp5hgcCQQCyrOS6vfXIUxKoWyvGyMyhqoLsiAdnxBKHh8tMINo0ioCbU+jc2dgPDipL0ym5nhvg5fCXZC2rvkKUltLEqq4PAkAqBf9b932EpKCkjFgyUq9nRCYhaeP6JbUPN3Z5e1bZ3zpfBjV4ViE0zJOMB6NcEvYpy2jNR/8rwRoUGsFPq8//AkAklw18RJyJuqFugsUzPznQvad0IuNJV7jnsmJqo6ur6NUvef6NA7ugUalNv9+imINjChO8HRLRQfRGk6B0D/P3AkBt54UBMtFefOLXgUdilwLdCUSw4KpbuBPw+cyWlMjcXCkj4rHoeksekyBH1GrBJkLqDMRqtVQUubuFwSzBAtlc"; //票通公钥(票通提供) private String ptPublicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCJkx3HelhEm/U7jOCor29oHsIjCMSTyKbX5rpoAY8KDIs9mmr5Y9r+jvNJH8pK3u5gNnvleT6rQgJQW1mk0zHuPO00vy62tSA53fkSjtM+n0oC1Fkm4DRFd5qJgoP7uFQHR5OEffMjy2qIuxChY4Au0kq+6RruEgIttb7wUxy8TwIDAQAB"; //3DES秘钥(票通提供) private final static String password = "lsBnINDxtct8HZB7KCMyhWSJ"; //请更换请求平台简称(票通提供) private final static String platform_alias = "DEMK"; //请更换请求平台编码(票通提供) private final static String platform_code = "11111111"; //销售方税号(测试环境票通提供,正式环境使用正式税号) private final static String taxpayerNum = "500102201007206608"; /** * @throws Exception * @title: testRSAGenerate * @description: RAS公钥私钥的生成 1024bit pkcs8格式 公钥提供给票通 私钥保留 */ @Test public void testRSAGenerate() throws Exception { KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA"); keyPairGen.initialize(1024); KeyPair keyPair = keyPairGen.generateKeyPair(); PublicKey publicKey = keyPair.getPublic(); PrivateKey privateKey = keyPair.getPrivate(); String publicKeyStr = RSAUtil.getKeyString(publicKey); System.out.println("publicKeyString:" + publicKeyStr); String privateKeyStr = RSAUtil.getKeyString(privateKey); System.out.println("privateKeyString:" + privateKeyStr); } /** * @title: testRealEstateRentalInvoiceBlue * @description: 蓝票接口调用 */ @Test public void testInvoiceBlue() throws Exception { String url = "http://fpkj.testnw.vpiaotong.cn/tp/openapi/invoiceBlue.pt"; Map map = new HashMap(); map.put("taxpayerNum", taxpayerNum); //销方税号 map.put("invoiceReqSerialNo", date(platform_alias));//发票请求流水号 map.put("buyerName", "购买方名称");//购买方名称 map.put("invoiceIssueKindCode", "82");//购买方名称 map.put("buyerTaxpayerNum", "XX0000000000000000");//购买方税号(非必填,个人发票传null) map.put("remark", "扫码");//购买方税号(非必填,个人发票传null) List> list = new ArrayList>(); Map listMapOne = new HashMap(); listMapOne.put("taxClassificationCode", "3040101000000000000");//税收分类编码(可以按照Excel文档填写) listMapOne.put("quantity", "1.00");//数量 listMapOne.put("goodsName", "研发服务");//货物名称 listMapOne.put("unitPrice", "10");//单价 listMapOne.put("invoiceIssueKindCode", "82");//发票种类 (注意:数电发票在81与82之间选择 )81:数电票(增值税专用发票)82:数电票(普通发票)10:增值税电子普通发票 listMapOne.put("invoiceAmount", "10");//金额 listMapOne.put("taxRateValue", "0.13");//税率(注:金税三期之后 不存在16% 与10%税率 16%自动会降为13% 10%自动降为9%) 如果使用一般人使用3% 或 5%税率请与财务确认是否享受了优惠政策 listMapOne.put("includeTaxFlag", "0");//含税标识 listMapOne.put("account", null);//数电账号,传入字段会指定开票员进行开票,不传则随机取一名开票员进行开票 (注: 开票员需要实现在票通登记) /** * 以下为零税率开票相关参数 * 零税商品为特殊税率,正式环境使用零税要事先与相关财务人员沟通该企业是否有零税商品,且适用那种零税状态 * (免税,不征税,普通零税率)其中一种 */ zeroGoodsformat(null, listMapOne);//零税商品类型 1:免税,2:不征税,3:普通零税率,4:简易征收,5:按5%简易征收.其它:非零税率, list.add(listMapOne); map.put("itemList", list); Gson gson = new Gson(); String content = gson.toJson(map); System.out.println(content); //OpenApi参数内容(3des秘钥(票通提供),平台编码(票通提供),平台前缀(票通提供),私钥) String buildRequest = this.buildRequestData(platform_code, platform_alias, content, password, privateKey); ; System.out.println(buildRequest); String response = HttpUtils.postJson(url, buildRequest); System.out.println(response); } /** * @title: testRealEstateRentalInvoiceBlue * @description: 蓝票接口调用(开具不动产租赁发票) 非特定业务无视即可. 停车费属于特定业务 * */ @Test public void testRealEstateRentalInvoiceBlue() throws Exception { String url = "http://fpkj.testnw.vpiaotong.cn/tp/openapi/invoiceBlue.pt"; Map map = new HashMap(); map.put("taxpayerNum", taxpayerNum); //销方税号 map.put("invoiceReqSerialNo", date(platform_alias));//发票请求流水号 map.put("buyerName", "购买方名称");//购买方名称 map.put("invoiceIssueKindCode", "82");//购买方名称 map.put("buyerTaxpayerNum", "XX0000000000000000");//购买方税号(非必填,个人发票传null) map.put("remark", "扫码");//购买方税号(非必填,个人发票传null) List> list = new ArrayList>(); Map listMapOne = new HashMap(); listMapOne.put("taxClassificationCode", "3040502020200000000");//税收分类编码(可以按照Excel文档填写) listMapOne.put("quantity", "1.00");//数量 listMapOne.put("goodsName", "*货物*货物名称");//货物名称 listMapOne.put("unitPrice", "10");//单价 listMapOne.put("invoiceIssueKindCode", "82");//发票种类 (注意:数电发票在81与82之间选择 )81:数电票(增值税专用发票)82:数电票(普通发票)10:增值税电子普通发票 listMapOne.put("invoiceAmount", "10");//金额 listMapOne.put("taxRateValue", "0.13");//税率(注:金税三期之后 不存在16% 与10%税率 16%自动会降为13% 10%自动降为9%) listMapOne.put("includeTaxFlag", "0");//含税标识 listMapOne.put("account", null);//数电账号,传入字段会指定开票员进行开票,不传则随机取一名开票员进行开票 (注: 开票员需要实现在票通登记) /** * 以下为零税率开票相关参数 * 零税商品为特殊税率,正式环境使用零税要事先与相关财务人员沟通该企业是否有零税商品,且适用那种零税状态 * (出口零税率,免税,不征税,普通零税率)其中一种 */ zeroGoodsformat(null, listMapOne);//零税商品类型 0:出口零税率,1:免税,2:不征税,3:普通零税率,4:简易征收,5:按5%简易征收.其它:非零税率, Map realEstateRentalService = new HashMap(); realEstateRentalService.put("region", "四川省绵阳市涪城区"); realEstateRentalService.put("detailedAddress", "东江北路 68 号"); realEstateRentalService.put("areaUnit", "平方米"); realEstateRentalService.put("crossCitySign", "0"); realEstateRentalService.put("leaseTerm", "2022-12-01 12:10 2022-12-12 15:00"); realEstateRentalService.put("titleNo", "无"); realEstateRentalService.put("carPlateNum", "京A4564651"); map.put("realEstateRentalService", realEstateRentalService);//购买方税号(非必填,个人发票传null) list.add(listMapOne); map.put("itemList", list); Gson gson = new Gson(); String content = gson.toJson(map); System.out.println(content); //OpenApi参数内容(3des秘钥(票通提供),平台编码(票通提供),平台前缀(票通提供),私钥) String buildRequest = this.buildRequestData(platform_code, platform_alias, content, password, privateKey); ; System.out.println(buildRequest); String response = HttpUtils.postJson(url, buildRequest); System.out.println(response); } /** * @title: testRegister * @description: 注册接口调用 */ @Test public void testRegister() throws Exception { String url = "http://fpkj.testnw.vpiaotong.cn/tp/openapi/register.pt"; Map map = new HashMap(); map.put("taxpayerNum", date(platform_alias));//销方纳税人识别号 测试注册时也请使用贵公司的企业税号进行注册 map.put("enterpriseName", "票通信息");//销方企业名称 map.put("legalPersonName", "AA");//法人名称 map.put("contactsName", "AA");//联系人名称 map.put("contactsEmail", "1121@qq.com");//联系人邮箱 map.put("contactsPhone", "15111111133");//联系人手机号 map.put("regionCode", "11");//地区编码 map.put("cityName", "海淀区");//市(区)名 map.put("enterpriseAddress", "地址");//详细地址 // TODO 请修改为正确的图片Base64传 map.put("taxRegistrationCertificate", "sdddddddddddddddddddd");//证件图片base64 Gson gson = new Gson(); String content = gson.toJson(map); System.out.println(content); //OpenApi参数内容(3des秘钥(票通提供),平台编码(票通提供),平台前缀(票通提供),私钥) String buildRequest = this.buildRequestData(platform_code, platform_alias, content, password, privateKey); System.out.println(buildRequest); String response = HttpUtils.postJson(url, buildRequest); String responseI = this.disposeResponse(response, ptPublicKey, password); System.out.println(response); System.out.println(responseI); } /** * @title: testInvoiceRed * @description: 红票接口调用 */ @Test public void testInvoiceRed() throws Exception { String url = "http://fpkj.testnw.vpiaotong.cn/tp/openapi/invoiceRed.pt"; Map map = new HashMap(); map.put("taxpayerNum", taxpayerNum);//销方税号(请于要冲红的蓝票税号一致) // TODO 请更换请求流水号前缀 map.put("invoiceReqSerialNo", platform_alias + "5678902234568904");//发票流水号 (唯一, 与蓝票发票流水号不一致) //(invoiceCode和invoiceNo) 与 (blueAllEleInvNo) 只能传一个 map.put("invoiceCode", "");//冲红发票的发票代码 原蓝票为税控发票时传递 map.put("invoiceNo", "");//冲红发票的发票号码 原蓝票为税控发票时传递 map.put("blueAllEleInvNo", "25019200000097980167");//冲红发票的发票号码 原蓝票为数电发票时传递 map.put("amount", "-11.30");//冲红金额 (要与原发票的总金额一致) // map.put("blueInvoiceDate", "20250101");//蓝票开票日期.冲红的原蓝票非票通开具的发票时候使用 map.put("redReason", "01");//冲红原因冲红原因,不传默认 01 01:开票有误 02:销货退回 03:服务中止 04:销售折让 map.put("invoiceKind", null);//发票种类 用于声明开具的红票是什么发票 不传跟随原蓝票的发票种类一致 (注意:数电发票在81与82之间选择 )81:数电票(增值税专用发票)82:数电票(普通发票)10:增值税电子普通发票 Gson gson = new Gson(); String content = gson.toJson(map); System.out.println(content); //OpenApi参数内容(3des秘钥(票通提供),平台编码(票通提供),平台前缀(票通提供),私钥) String buildRequest = this.buildRequestData(platform_code, platform_alias, content, password, privateKey); ; System.out.println(buildRequest); String response = HttpUtils.postJson(url, buildRequest); System.out.println(response); } /** * @title: testAuthWeChatCards * @description:查询发票 */ @Test public void testqueryInvoice() throws Exception { String url = "http://fpkj.testnw.vpiaotong.cn/tp/openapi/queryInvoice.pt"; // String url = "http://fpkj.testnw.vpiaotong.cn/tp/openapi/queryInvoiceInfo.pt"; //查询发票票面全面信息地址 Map map = new HashMap(); map.put("taxpayerNum", taxpayerNum);//销方税号(要跟被查询的发票税号一致) // TODO 请更换请求流水号前缀 map.put("invoiceReqSerialNo", platform_alias + "2025021811251811");//发票流水号 (查询的红票或者蓝票开具时所填写的invoiceReqSerialNo一致) Gson gson = new Gson(); String content = gson.toJson(map); //OpenApi参数内容(3des秘钥(票通提供),平台编码(票通提供),平台前缀(票通提供),私钥) String buildRequest = this.buildRequestData(platform_code, platform_alias, content, password, privateKey); ; System.out.println(buildRequest); String response = HttpUtils.postJson(url, buildRequest); System.out.println(response); System.out .println(this.disposeResponse(response, ptPublicKey, password)); } @Test public void testgetUnLoginUrl() throws Exception { String url = "http://fpkj.testnw.vpiaotong.cn/tp/openapi/getUnLoginUrl.pt"; // String url = "http://fpkj.testnw.vpiaotong.cn/tp/openapi/queryInvoiceInfo.pt"; //查询发票票面全面信息地址 Map map = new HashMap(); map.put("taxpayerNum", taxpayerNum);//销方税号(要跟被查询的发票税号一致) // TODO 请更换请求流水号前缀 map.put("redirectUrl", "jtgl.piaotong.vip");//发票流水号 (查询的红票或者蓝票开具时所填写的invoiceReqSerialNo一致) map.put("customData", "jtgl.piaotong.vip"); Gson gson = new Gson(); String content = gson.toJson(map); //OpenApi参数内容(3des秘钥(票通提供),平台编码(票通提供),平台前缀(票通提供),私钥) String buildRequest = this.buildRequestData(platform_code, platform_alias, content, password, privateKey); ; System.out.println(buildRequest); String response = HttpUtils.postJson(url, buildRequest); System.out.println(response); System.out .println(this.disposeResponse(response, ptPublicKey, password)); } @Test public void testgetUnAuthUrl() throws Exception { String url = "http://fpkj.testnw.vpiaotong.cn/tp/openapi/getUnAuthUrl.pt"; // String url = "http://fpkj.testnw.vpiaotong.cn/tp/openapi/queryInvoiceInfo.pt"; //查询发票票面全面信息地址 Map map = new HashMap(); map.put("taxpayerNum", taxpayerNum);//销方税号(要跟被查询的发票税号一致) // TODO 请更换请求流水号前缀 map.put("token", "9297dbfcd1ff4b179d56406453a3c9f9");//发票流水号 (查询的红票或者蓝票开具时所填写的invoiceReqSerialNo一致) // map.put("customData", "jtgl.piaotong.vip"); Gson gson = new Gson(); String content = gson.toJson(map); //OpenApi参数内容(3des秘钥(票通提供),平台编码(票通提供),平台前缀(票通提供),私钥) String buildRequest = this.buildRequestData(platform_code, platform_alias, content, password, privateKey); ; System.out.println(buildRequest); String response = HttpUtils.postJson(url, buildRequest); System.out.println(response); System.out .println(this.disposeResponse(response, ptPublicKey, password)); } /** * @title: testGetInvoiceQrAndExtractCode * @description: 获取多项目开票二维码和提取码接口 */ @Test public void testGetInvoiceIssueQrcodeItems() throws Exception { String url = "http://fpkj.testnw.vpiaotong.cn/tp/openapi/getInvoiceIssueQrcode.pt"; Map map = new HashMap(); map.put("taxpayerNum", taxpayerNum); //销方纳税人识别号 map.put("enterpriseName", taxpayerNum); //销方企业名称 如实填写 测试环境环境提供的测试税号名称与税号恰好一致. 正式环境不要模仿 map.put("qrcodeNo", date(platform_alias));//二维码编号(唯一) map.put("tradeNo", "DEMO12345678900");//订单号 map.put("tradeTime", "2017-06-26 09:15:54"); //交易时间 map.put("invoiceAmount", "3"); //发票金额(含税) map.put("casherName", "收款人A"); //收款人姓名(校验规则: 中文/字母大小写/及其两者组合) map.put("reviewerName", "审核人A"); //审核人姓名(校验规则: 中文/字母大小写/及其两者组合) map.put("drawerName", "开票人A"); //开票人姓名(校验规则: 中文/字母大小写/及其两者组合) map.put("allowInvoiceCount", "1"); //允许开票张数(非必填 默认值:1) map.put("definedData", "所填软件"); // map.put("smsFlag", "false"); //是否发送短信 (非必填 默认值:false 测试环境不发送短信) // map.put("expireTime", ""); //有效时间 (非必填 默认值:永久有效 填写格式 yyyy-MM-dd HH:mm:ss) // map.put("email","XXXXX@XX.com"); //二维码发送邮箱地址(非必填) //其他参数见接口文档 //可选发票种类及分机列表信息 List> invoiceIssueOptionsList = new ArrayList>(); Map invoiceIssueOptionsMap = new HashMap(); invoiceIssueOptionsMap.put("invoiceType", "82");//可选发票种类 10税控电普 08税控电专 82数电普票 81数电纸票 // invoiceIssueOptionsMap.put("extensionNum","0");//分机号 // invoiceIssueOptionsMap.put("machineCode",null);//机器编码 invoiceIssueOptionsList.add(invoiceIssueOptionsMap); map.put("invoiceIssueOptions", invoiceIssueOptionsList); //商品行 List> list = new ArrayList>(); Map listMapOne = new HashMap(); listMapOne.put("itemName", "小麦"); //开票项目名 listMapOne.put("taxRateValue", "0.13"); //税率(注:金税三期之后 不存在16% 与10%税率 16%自动会降为13% 10%自动降为9%) listMapOne.put("taxClassificationCode", "1010101020000000000");//税收分类编码 listMapOne.put("quantity", "1"); //数量 listMapOne.put("unitPrice", "2"); //单价 listMapOne.put("invoiceItemAmount", "2"); //金额 Map listMapTwo = new HashMap(); listMapTwo.put("itemName", "大米"); listMapTwo.put("taxRateValue", "0.13"); listMapTwo.put("taxClassificationCode", "1010101020000000000"); listMapTwo.put("quantity", "1"); listMapTwo.put("unitPrice", "1"); listMapTwo.put("invoiceItemAmount", "1"); list.add(listMapOne); list.add(listMapTwo); map.put("itemList", list); Gson gson = new Gson(); String content = gson.toJson(map); //OpenApi参数内容(3des秘钥(票通提供),平台编码(票通提供),平台前缀(票通提供),私钥) String buildRequest = this.buildRequestData(platform_code, platform_alias, content, password, privateKey); ; String response = HttpUtils.postJson(url, buildRequest); System.out.println(response); System.out .println(this.disposeResponse(response, ptPublicKey, password)); } /** * @title: queryInvoiceQrCode * @description:查询二维码信息 */ @Test public void queryInvoiceQrCode() throws Exception { String url = "http://fpkj.testnw.vpiaotong.cn/tp/openapi/queryInvoiceQrCode.pt"; HashMap map = new HashMap(); map.put("taxpayerNum", taxpayerNum);//销方税号 map.put("tradeNo", "DEMO2019090916264942");//订单号 map.put("invoiceAmount", "3");//金额 Gson gson = new Gson(); String content = gson.toJson(map); System.out.println(content); //OpenApi参数内容(3des秘钥(票通提供),平台编码(票通提供),平台前缀(票通提供),私钥) String buildRequest = this.buildRequestData(platform_code, platform_alias, content, password, privateKey); ; String response = HttpUtils.postJson(url, buildRequest); System.out.println(response); System.out .println(this.disposeResponse(response, ptPublicKey, password)); } /** * @title: testdeleteInvoiceQrCode * @description: 作废二维码接口 */ @Test public void testdeleteInvoiceQrCode() throws Exception { String url = "http://fpkj.testnw.vpiaotong.cn/tp/openapi/deleteInvoiceQrCode.pt"; List> list = new ArrayList>(); Map map = new HashMap(); map.put("taxpayerNum", taxpayerNum); //销方税号 map.put("enterpriseName", taxpayerNum);//企业名称 如实填写 测试环境环境提供的测试税号名称与税号恰好一致. 正式环境不要模仿 map.put("tradeNo", "CTXP2018091910241715");//与开票二维码的订单号一致 map.put("tradeTime", "2017-06-26 09:15:54"); //与开票二维码的时间一致 map.put("invoiceAmount", "1.00");//金额一致 list.add(map); Gson gson = new Gson(); String content = gson.toJson(map); //OpenApi参数内容(3des秘钥(票通提供),平台编码(票通提供),平台前缀(票通提供),私钥) String buildRequest = this.buildRequestData(platform_code, platform_alias, content, password, privateKey); ; System.out.println(buildRequest); String response = HttpUtils.postJson(url, buildRequest); System.out.println(response); System.out .println(this.disposeResponse(response, ptPublicKey, password)); } /** * @title: testAuthWeChatCards * @description:查询发票抬头信息 */ @Test public void testTitleInfo() throws Exception { String url = "http://fpkj.testnw.vpiaotong.cn/tp/openapi/getInvoiceTitleInfo.pt"; String content = "{\"enterpriseName\":\"北京票通\"}"; //OpenApi参数内容(3des秘钥(票通提供),平台编码(票通提供),平台前缀(票通提供),私钥) String buildRequest = this.buildRequestData(platform_code, platform_alias, content, password, privateKey); ; System.out.println(buildRequest); String response = HttpUtils.postJson(url, buildRequest); System.out.println(response); System.out .println(this.disposeResponse(response, ptPublicKey, password)); } /** * @title: testAuthWeChatCards * @description:微信卡包授 */ @Test public void testAuthWeChatCards() throws Exception { String url = "http://fpkj.testnw.vpiaotong.cn/tp/openapi/authWeChatCards.pt"; Map map = new HashMap(); map.put("taxpayerNum", taxpayerNum);//销方税号(要跟被查询的发票税号一致) // TODO 请更换请求流水号前缀 map.put("invoiceReqSerialNo", platform_alias + "2025021811251811");//发票流水号 (查询的红票或者蓝票开具时所填写的invoiceReqSerialNo一致) Gson gson = new Gson(); String content = gson.toJson(map); //OpenApi参数内容(3des秘钥(票通提供),平台编码(票通提供),平台前缀(票通提供),私钥) String buildRequest = this.buildRequestData(platform_code, platform_alias, content, password, privateKey); ; String response = HttpUtils.postJson(url, buildRequest); System.out.println(response); System.out .println(this.disposeResponse(response, ptPublicKey, password)); } /** * @title: queryInvoiceQrCode * @description:重发短信接口 */ @Test public void resendEmailOrSMS() throws Exception { String url = "http://fpkj.testnw.vpiaotong.cn/tp/openapi/resendEmailOrSMS.pt"; HashMap map = new HashMap(); map.put("taxpayerNum", taxpayerNum);//销方税号 map.put("invoiceReqSerialNo", "DEMO2019090916264942");//流水号 注:发票请求流水号和发票代码号码不能同时为空,如果都填写以发票请求流水号为准 map.put("invoiceCode", "3");//发票代码 map.put("invoiceNo", "3");//发票号码 map.put("takerEmail", "3");// 收票人邮箱,不传的话默认使用开具时传的收票人邮箱 map.put("takerTel", "3");// 收票人手机号,无默认,需要校验企业是否开通发送短信。 Gson gson = new Gson(); String content = gson.toJson(map); System.out.println(content); //OpenApi参数内容(3des秘钥(票通提供),平台编码(票通提供),平台前缀(票通提供),私钥) String buildRequest = this.buildRequestData(platform_code, platform_alias, content, password, privateKey); ; String response = HttpUtils.postJson(url, buildRequest); System.out.println(response); System.out .println(this.disposeResponse(response, ptPublicKey, password)); } /** * * * 以下为数电专用接口 * */ /** * @title: testregisterUser * @description:用户登记接口 */ @Test public void testregisterUser() throws Exception { String url = "http://fpkj.testnw.vpiaotong.cn/tp/openapi/registerUser.pt"; HashMap map = new HashMap(); map.put("taxpayerNum", taxpayerNum);//销方税号 map.put("loginMethod", "1");//登录方式。1:用户名(居民身份证号码/手机号码/用户名)+密码 只有1 map.put("account", "DEMOadmin");//电子税局登录账号(手机号或身份证号),若平台已经存在做更新操作 map.put("password", SecurityUtil.encrypt3DES(password, "ispassword"));//电子税局登录密码 3DES 加密 map.put("identityType", "01");// 登录身份类型. 要与电子税局身份一致 01:法定代表人02:财务负责人03:办税员 04:涉税服务人员05:管理员07:领票人09:开票员99:其他人员 map.put("identityPwd", null);// 登录身份密码 (只有部分地区需要.目前多数区域不需要,预留不传值) map.put("phoneNum", "13000000000");// 手机号码。当前登记用户的手机号。如果是手机号+密码登录,该值必须和 account 一致 map.put("name", "测试");//姓名 最好要跟登记的数电账户对应的开票人一致 map.put("operationType", null);// 操作类型。默认 1 登记。 1:登记;2:删除 多数情况下不传 Gson gson = new Gson(); String content = gson.toJson(map); System.out.println(content); //OpenApi参数内容(3des秘钥(票通提供),平台编码(票通提供),平台前缀(票通提供),私钥) String buildRequest = this.buildRequestData(platform_code, platform_alias, content, password, privateKey); ; String response = HttpUtils.postJson(url, buildRequest); System.out.println(response); System.out .println(this.disposeResponse(response, ptPublicKey, password)); } /** * @title: sendLoginSmsCode * @description:获取登录短信验证码 */ @Test public void sendLoginSmsCode() throws Exception { String url = "http://fpkj.testnw.vpiaotong.cn/tp/openapi/sendLoginSmsCode.pt"; HashMap map = new HashMap(); map.put("taxpayerNum", taxpayerNum);//销方税号 map.put("account", "DEMOadmin");//电子税局登录账号(手机号或身份证号),若平台已经存在做更新操作 Gson gson = new Gson(); String content = gson.toJson(map); System.out.println(content); //OpenApi参数内容(3des秘钥(票通提供),平台编码(票通提供),平台前缀(票通提供),私钥) String buildRequest = this.buildRequestData(platform_code, platform_alias, content, password, privateKey); ; String response = HttpUtils.postJson(url, buildRequest); System.out.println(response); System.out .println(this.disposeResponse(response, ptPublicKey, password)); } /** * @title: smsLogin * @description:短信登录 */ @Test public void smsLogin() throws Exception { String url = "http://fpkj.testnw.vpiaotong.cn/tp/openapi/smsLogin.pt"; HashMap map = new HashMap(); map.put("taxpayerNum", taxpayerNum);//销方税号 map.put("account", "DEMOadmin");//电子税局登录账号(手机号或身份证号),若平台已经存在做更新操作 map.put("smsCode", "123456");//短信验证码 Gson gson = new Gson(); String content = gson.toJson(map); System.out.println(content); //OpenApi参数内容(3des秘钥(票通提供),平台编码(票通提供),平台前缀(票通提供),私钥) String buildRequest = this.buildRequestData(platform_code, platform_alias, content, password, privateKey); ; String response = HttpUtils.postJson(url, buildRequest); System.out.println(response); System.out .println(this.disposeResponse(response, ptPublicKey, password)); } /** * @title: getAuthenticationQrcode * @description:获取实名认证二维码 */ @Test public void getAuthenticationQrcode() throws Exception { String url = "http://fpkj.testnw.vpiaotong.cn/tp/openapi/getAuthenticationQrcode.pt"; HashMap map = new HashMap(); map.put("taxpayerNum", taxpayerNum);//销方税号 map.put("account", "DEMOadmin");//电子税局登录账号(手机号或身份证号),若平台已经存在做更新操作 map.put("qrcodeType", "1");//二维码类型 1:税务 APP; 2:个人所得税 APP .不传值默认 1 税务 APP。 Gson gson = new Gson(); String content = gson.toJson(map); System.out.println(content); //OpenApi参数内容(3des秘钥(票通提供),平台编码(票通提供),平台前缀(票通提供),私钥) String buildRequest = this.buildRequestData(platform_code, platform_alias, content, password, privateKey); ; String response = HttpUtils.postJson(url, buildRequest); System.out.println(response); System.out .println(this.disposeResponse(response, ptPublicKey, password)); } /** * @title: queryAuthQrcodeScanStatus * @description:查询实名认证二维码扫码状态 */ @Test public void queryAuthQrcodeScanStatus() throws Exception { String url = "http://fpkj.testnw.vpiaotong.cn/tp/openapi/queryAuthQrcodeScanStatus.pt"; HashMap map = new HashMap(); map.put("taxpayerNum", taxpayerNum);//销方税号 map.put("account", "DEMOadmin");//电子税局登录账号(手机号或身份证号),若平台已经存在做更新操作 map.put("authId", "1");//认证 id,推送开票结果/查询开票结果/获取实名认证二维码时会随二维码一起返回 Gson gson = new Gson(); String content = gson.toJson(map); System.out.println(content); //OpenApi参数内容(3des秘钥(票通提供),平台编码(票通提供),平台前缀(票通提供),私钥) String buildRequest = this.buildRequestData(platform_code, platform_alias, content, password, privateKey); ; String response = HttpUtils.postJson(url, buildRequest); System.out.println(response); System.out .println(this.disposeResponse(response, ptPublicKey, password)); } /** * @title: getTaxBureauAccountAuthStatus * @description:查询数电账号认证状态 */ @Test public void getTaxBureauAccountAuthStatus() throws Exception { String url = "http://fpkj.testnw.vpiaotong.cn/tp/openapi/getTaxBureauAccountAuthStatus.pt"; HashMap map = new HashMap(); map.put("taxpayerNum", taxpayerNum);//销方税号 map.put("account", "DEMOadmin");//电子税局登录账号(手机号或身份证号),若平台已经存在做更新操作 Gson gson = new Gson(); String content = gson.toJson(map); System.out.println(content); //OpenApi参数内容(3des秘钥(票通提供),平台编码(票通提供),平台前缀(票通提供),私钥) String buildRequest = this.buildRequestData(platform_code, platform_alias, content, password, privateKey); ; String response = HttpUtils.postJson(url, buildRequest); System.out.println(response); System.out .println(this.disposeResponse(response, ptPublicKey, password)); } /** * * 以下为税控专用接口 * */ /** * @title: testGetPTBoxStatus * @description: 获取票通宝状态接口 */ @Test public void testGetPTBoxStatus() throws Exception { String url = "http://fpkj.testnw.vpiaotong.cn/tp/openapi/getPTBoxStatus.pt"; String content = "{\"taxpayerNum\":\"110105201606160003\",\"enterpriseName\":\"110105201606160003\"}"; //OpenApi参数内容(3des秘钥(票通提供),平台编码(票通提供),平台前缀(票通提供),私钥) String buildRequest = this.buildRequestData(platform_code, platform_alias, content, password, privateKey); ; String response = HttpUtils.postJson(url, buildRequest); System.out.println(response); System.out .println(this.disposeResponse(response, ptPublicKey, password)); } /** * @title: testGetInvoiceRepertoryInfo * @description: 获取库存接口 */ @Test public void testGetInvoiceRepertoryInfo() throws Exception { String url = "http://fpkj.testnw.vpiaotong.cn/tp/openapi/getInvoiceRepertoryInfo.pt"; Map map = new HashMap(); map.put("taxpayerNum", taxpayerNum);//销方税号(要跟被查询的发票税号一致) // TODO 请更换请求流水号前缀 map.put("enterpriseName", taxpayerNum);//企业名称 如实填写 测试环境环境提供的测试税号名称与税号恰好一致. 正式环境不要模仿 Gson gson = new Gson(); String content = gson.toJson(map); //OpenApi参数内容(3des秘钥(票通提供),平台编码(票通提供),平台前缀(票通提供),私钥) String buildRequest = this.buildRequestData(platform_code, platform_alias, content, password, privateKey); ; String response = HttpUtils.postJson(url, buildRequest); System.out.println(response); System.out .println(this.disposeResponse(response, ptPublicKey, password)); } /** * @title: revokeInvoiceIssue * @description:撤销开票 */ @Test public void revokeInvoiceIssue() throws Exception { String url = "http://fpkj.testnw.vpiaotong.cn/tp/openapi/revokeInvoiceIssue.pt"; String content = "{\"taxpayerNum\":\"110105201606160003\",\"invoiceReqSerialNo\":\"DEMO2019090916515155\"}"; //OpenApi参数内容(3des秘钥(票通提供),平台编码(票通提供),平台前缀(票通提供),私钥) String buildRequest = this.buildRequestData(platform_code, platform_alias, content, password, privateKey); ; String response = HttpUtils.postJson(url, buildRequest); System.out.println(response); System.out .println(this.disposeResponse(response, ptPublicKey, password)); } /** * * 以下为便捷工具 ,非调用接口 */ /** * @title: test3DES * @description: 3DES加密 */ @Test public void test3DES() throws Exception { String content = "{\"taxpayerNum\": \"9120931023801231\",\"enterpriseName\": \"西单大悦城有限公司\",\"paymentTransID\": \"12109238102831023102983\",\"paymentType\": \"2\",\"paymentTransTime\": \"2017-01-19 18:20:09\",\"paymentTransMoney\": \"20\",\"orderID\": \"12109238102831023102981\",\"orderMoney\": \"30\"}"; System.out.println(SecurityUtil.encrypt3DES(password, content)); } /** * @title: test3DESDecry * @description: 3DES解密 */ @Test public void test3DESDecry() throws Exception { String str = "WkoTqkd08kNxEFqY6bTa/LVHoAj8nYPWJrX8KmI4rrFmJWXMlk5ik7QzwNTvN1Yiq5sGyS17ShQk6UdhwH5XftxVY9W3ytRZr35bic05cZBlq6VejY2AH9Ql5zZu/4xipBD1jTT/6CBeFU5ViYDbGChpDYf8hEVO4JQQl/H5a1SkwtEaPKT8BCQAvy2Sn0ffmCc0NPjaFWASk2bkqM1NzCqFt6BXUjao34IWG2IzUl9O/VXYFAItC/c67lLXu0ziTTK2n0FGLABED5V9uHvhNCvALC81PH1Fd+3KT11i1szg/F79DbzQOK8WrdSnsUSPbyPFC5kA4MbS1xuqEOHsgSBhw0/xPjpq4ODQwPRwjRI=\n"; System.out.println(SecurityUtil.decrypt3DES(password, str)); } /** * @title: testBase64 * @description: Base64编码 */ @Test public void testBase64() throws Exception { String str = "JJON0d93C9nQN013N+cCwwIYbRVYlWChGQkSgAWG8g4mD1xFU6oGPauqih5gW7ZTcpejSPS8TqRbdBFdBATSXdwZqPM0q8sVYf3xwlp8OEw6INcUCvRW7myiFkzSJLV4Ost42d5Xp+sicgMj0bn99BsRSqe06BMvYTA46L/vGGPqN4tuuy2B/enpkGLcOQdPdtC+wG8ub6+zykisJT5I7EMls73cjaSlj1iRw/PT9huULu97iPHIiqnKhK05AXkvgWMcfg42+bLeG/kPgbaAtwAkXN/yDkKACcDML2WE8TZ+BFsaQPbH+BfY/XQ4VXSYF5NGeulhDJr1DLIHgH+KNQ=="; System.out.println(encode2String(str)); } /** * @title: testBase64 * @description: Base64解码 */ @Test public void testBase64toURL() throws Exception { String str = "SkpPTjBkOTNDOW5RTjAxM04rY0N3d0lZYlJWWWxXQ2hHUWtTZ0FXRzhnNG1EMXhGVTZvR1BhdXFpaDVnVzdaVGNwZWpTUFM4VHFSYmRCRmRCQVRTWGR3WnFQTTBxOHNWWWYzeHdscDhPRXc2SU5jVUN2Ulc3bXlpRmt6U0pMVjRPc3Q0MmQ1WHArc2ljZ01qMGJuOTlCc1JTcWUwNkJNdllUQTQ2TC92R0dQcU40dHV1eTJCL2VucGtHTGNPUWRQZHRDK3dHOHViNit6eWtpc0pUNUk3RU1sczczY2phU2xqMWlSdy9QVDlodVVMdTk3aVBISWlxbktoSzA1QVhrdmdXTWNmZzQyK2JMZUcva1BnYmFBdHdBa1hOL3lEa0tBQ2NETUwyV0U4VForQkZzYVFQYkgrQmZZL1hRNFZYU1lGNU5HZXVsaERKcjFETElIZ0grS05RPT0="; System.out.println(decode2String(str)); } public String decode2String(String targetString) throws UnsupportedEncodingException { byte[] decodedBytes = Base64.getDecoder().decode(targetString); String decodedString = new String(decodedBytes); return decodedString; } public String encode2String(String targetString) throws UnsupportedEncodingException { return Base64.getEncoder().encodeToString(targetString.getBytes()); } /** * @param s 零税商品类型 0:出口零税率,1:免税,2:不征税,3:普通零税率,4:简易征收,5:按5%简易征收.其它:非零税率, * @param listMapOne */ private void zeroGoodsformat(String s, Map listMapOne) { if ("1".equals(s)) { listMapOne.put("taxRateValue", "0"); listMapOne.put("zeroTaxFlag", "1");//零税率标识(空:非零税率,0:出口零税率,1:免税,2:不征税,3:普通零税率) listMapOne.put("preferentialPolicyFlag", "1");//优惠政策标识(空:不使用,1:使用) 注:零税率标识传非空 此字段必须填写为"1" listMapOne.put("vatSpecialManage", "免税");//增值税特殊管理(preferentialPolicyFlag为1 此参数必填) } else if ("0".equals(s)) { listMapOne.put("taxRateValue", "0"); listMapOne.put("zeroTaxFlag", "0");//零税率标识(空:非零税率,0:出口零税率,1:免税,2:不征税,3:普通零税率) listMapOne.put("preferentialPolicyFlag", "1");//优惠政策标识(空:不使用,1:使用) 注:零税率标识传非空 此字段必须填写为"1" listMapOne.put("vatSpecialManage", "出口零税");//增值税特殊管理(preferentialPolicyFlag为1 此参数必填) } else if ("2".equals(s)) { listMapOne.put("taxRateValue", "0"); listMapOne.put("zeroTaxFlag", "2");//零税率标识(空:非零税率,0:出口零税率,1:免税,2:不征税,3:普通零税率) listMapOne.put("preferentialPolicyFlag", "1");//优惠政策标识(空:不使用,1:使用) 注:零税率标识传非空 此字段必须填写为"1" listMapOne.put("vatSpecialManage", "不征税");//增值税特殊管理(preferentialPolicyFlag为1 此参数必填) } else if ("3".equals(s)) { listMapOne.put("taxRateValue", "0"); listMapOne.put("zeroTaxFlag", "3");//零税率标识(空:非零税率,0:出口零税率,1:免税,2:不征税,3:普通零税率) listMapOne.put("preferentialPolicyFlag", null);//优惠政策标识(空:不使用,1:使用) 注:零税率标识传非空 此字段必须填写为"1" listMapOne.put("vatSpecialManage", null);//增值税特殊管理(preferentialPolicyFlag为1 此参数必填) } else if ("4".equals(s)) { listMapOne.put("preferentialPolicyFlag", "1");//优惠政策标识(空:不使用,1:使用) 注:零税率标识传非空 此字段必须填写为"1" listMapOne.put("vatSpecialManage", "简易征收");//增值税特殊管理(preferentialPolicyFlag为1 此参数必填) } else if ("5".equals(s)) { listMapOne.put("taxRateValue", "0.05"); listMapOne.put("preferentialPolicyFlag", "1");//优惠政策标识(空:不使用,1:使用) 注:零税率标识传非空 此字段必须填写为"1" listMapOne.put("vatSpecialManage", "按5%简易征收");//增值税特殊管理(preferentialPolicyFlag为1 此参数必填) } else { listMapOne.put("zeroTaxFlag", null);//零税率标识(空:非零税率,0:出口零税率,1:免税,2:不征税,3:普通零税率) listMapOne.put("preferentialPolicyFlag", null);//优惠政策标识(空:不使用,1:使用) 注:零税率标识传非空 此字段必须填写为"1" listMapOne.put("vatSpecialManage", null);//增值税特殊管理(preferentialPolicyFlag为1 此参数必填) } } public String buildRequestData(String platformCode, String prefix, String content, String password, String privateKey) throws Exception { Map map = new HashMap(); String reqContent = SecurityUtil.encrypt3DES(password, content); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); map.put("platformCode", platformCode); map.put("signType", "RSA"); map.put("format", "JSON"); map.put("version", "1.0"); map.put("content", reqContent); map.put("timestamp", sdf.format(new Date())); map.put("serialNo", date(prefix)); map.put("sign", RSAUtil.sign(RSAUtil.getSignatureContent(map), privateKey)); Gson gson = new Gson(); return gson.toJson(map); } public String disposeResponse(String jsonStr, String publicKey, String password) { JsonObject jsonObject = (new JsonParser()).parse(jsonStr).getAsJsonObject(); Gson gson = new Gson(); HashMap map = gson.fromJson(jsonStr, HashMap.class); String sign = (String) map.remove("sign"); if (RSAUtil.verify(RSAUtil.getSignatureContent(map), sign, publicKey)) { String plainContent = SecurityUtil.decrypt3DES(password, (String) map.get("content")); jsonObject.add("content", (new JsonParser()).parse(plainContent)); return jsonObject.toString(); } else { throw new IllegalStateException("验签失败"); } } public String date(String prefix) { Date date = new Date(); SimpleDateFormat sdf = new SimpleDateFormat("YYYYMMddHHmmss"); String str = prefix + sdf.format(date) + (int) (Math.random() * 90 + 10); System.out.println(str); return str; } }