赞
踩
整合发票第三方–实现自助开票相关功能
码农门,你们好,今天要介绍的是一个第三方的API,主要是用于自助开票或开票系统的相关功能设计。我在项目中用到的是诺诺发票,感觉功能还是比较完善的。具体网址和第三方API文档可以参考诺诺发票官网----->>>>
首先,需要成为诺诺开放平台的会员,并完成认证审核(需要税号);这些工作做完之后,就可以创建应用,接入sdk进行开发。有一些注意的点需要留意:
1.开发者的APP证书(包含APP Key 和 APP Secret)需要保存好
2.应用token选择
(1)如果是自己用,或者对于token没有相关安全限制的,可以选择固定token。但是相对安全性较低,但是开发测试比较方便。
(2)如果是企业服务使用,建议使用动态token,但是要做好token存储,这个token是有限制的,每个令牌是存在有效期(24小时)的,且令牌30天内的调用上限为50次。我在项目中,使用的是redis存储在缓存中。
1.yaml配置文件
##发票接口参数---测试
invoice:
# 接口地址(测试地址)
baseURL: https://sandbox.nuonuocs.cn/open/v1/services
# 上文所述需要保存的APP证书
APPKey: 123456789
APPSecret: 123456789
# 销方税号(即开票方税号)
taxnum: 123456789
2.代码注入配置
//从缓存中获取token
private String accessTokenKey = "invoice_accessToken";
@Value("${invoice.baseURL}")
private String baseURL;
@Value("${invoice.APPKey}")
private String aPPKey;
@Value("${invoice.APPSecret}")
private String aPPSecret;
@Value("${invoice.taxnum}")
private String taxnum;
public String getToken() { try { Object object = cacheService.getDataWithKey(accessTokenKey); //Object object = null;如果放开这串代码,表明不走缓存,直接请求获取token if(object!=null){ return object.toString(); }else { String token = NNOpenSDK.getIntance().getMerchantToken(aPPKey,aPPSecret); JSONObject jsonObject = JSONObject.parseObject(token); String accessToken = jsonObject.getString("access_token"); if (ObjectUtil.isNotEmpty(accessToken)){ cacheService.setDataWithParams(accessTokenKey,accessToken,24, TimeUnit.HOURS); log.info("invoice_accessToken =========>"); return accessToken; }else { throw new HbsxException("获取token失败"); } } } catch (Exception e){ log.error("InvoiceSettingServiceImpl.getToken.error==>{}",e.getMessage()); if(e instanceof XXXException){ throw new XXXException(ErrorCode.SYSTEM_ERROR.getCode(),e.getMessage()); } throw new XXXException(ErrorCode.SYSTEM_ERROR.getCode(),"系统异常,请稍后再试!"); } }
1.这是请求开具发票的一些相关请求参数
2.电子发票不存在作废,只能冲红,冲红也是一种开票,只不过票面类型为红票,所以接口与开蓝票接口一致,仅参数不同。
3.返回参数为发票流水号,开票结果可以用此参数作为唯一标识查询,需要保存。
4.开票接口返回的异常码需要捕捉:
5.示例代码
/** * 开具发票 * @param invoiceSettingDTO * @param request */ @Override @Transactional(rollbackFor = HbsxException.class) public Map<String,Object> createFP(InvoiceSettingDTO invoiceSettingDTO, HttpServletRequest request) { try { Map<String,Object> map = new HashMap<>(); String token = getToken(); NNOpenSDK sdk = NNOpenSDK.getIntance(); String method = "nuonuo.electronInvoice.requestBillingNew";//API方法名 InvoiceSetting detail = this.getDetail(); String url = baseURL; //SDK请求地址 JSONObject order = new JSONObject(); JSONObject jsonObject = new JSONObject(); order.put("buyerName",invoiceSettingDTO.getInvoiceTitle()); //纳税人识别号 if (ObjectUtil.isNotEmpty(invoiceSettingDTO.getTaxPayerId())&&invoiceSettingDTO.getTitleType().equals("2")){ order.put("buyerTaxNum",invoiceSettingDTO.getTaxPayerId()); } //电话 if (ObjectUtil.isNotEmpty(invoiceSettingDTO.getCtel())&&invoiceSettingDTO.getTitleType().equals("2")){ order.put("buyerTel",invoiceSettingDTO.getCtel()); } //地址 if (ObjectUtil.isNotEmpty(invoiceSettingDTO.getAddress())&&invoiceSettingDTO.getTitleType().equals("2")){ order.put("buyerAddress",invoiceSettingDTO.getAddress()); } //开户行和卡号 if (ObjectUtil.isNotEmpty(invoiceSettingDTO.getBankName())&&ObjectUtil.isNotEmpty(invoiceSettingDTO.getBankaccountname())&&invoiceSettingDTO.getTitleType().equals("2")){ order.put("buyerAccount",invoiceSettingDTO.getBankName()+invoiceSettingDTO.getBankaccountname()); } order.put("salerTaxNum",detail.getTaxPayerId()); order.put("salerTel",detail.getCtel()); order.put("salerAddress",detail.getAddress()); order.put("salerAccount",detail.getBankName()+detail.getBankaccountname()); order.put("orderNo",invoiceSettingDTO.getOrderId()); order.put("invoiceDate",invoiceSettingDTO.getOrderTime()); order.put("checker",detail.getReviewedName()); order.put("payee",detail.getPayeeName()); order.put("clerk",detail.getDrawerName()); order.put("pushMode","-1"); order.put("invoiceType","1"); JSONObject invoiceDetail = new JSONObject(); //单价和数量 invoiceDetail.put("price",invoiceSettingDTO.getPayedFee()); invoiceDetail.put("num","1"); //invoiceDetail.put("goodsName",invoiceSettingDTO.getCname()); invoiceDetail.put("withTaxFlag","1"); invoiceDetail.put("taxExcludedAmount",invoiceSettingDTO.getPayedFee()); invoiceDetail.put("taxRate",detail.getActivityTaxrate()); order.put("invoiceDetail",invoiceDetail); jsonObject.put("order",order); String content = jsonObject.toJSONString(); String senid = UUID.randomUUID().toString().replace("-", ""); // 唯一标识,由企业自己生成32位随机码 String json = sdk.sendPostSyncRequest(url, senid, aPPKey, aPPSecret, token, taxnum, method, content); JSONObject result = JSONObject.parseObject(json); String code = result.getString("code"); System.out.println(json+"==========>>"); System.out.println(json+"==========>>"); System.out.println(json+"==========>>"); if (!code.equals("E0000")){ String errormsg = result.getString("describe"); throw new XXXException(errormsg+",开票失败,请稍后再试"); }else { JSONObject result1 = result.getJSONObject("result"); //获取发票流水号 String invoiceSerialNum = result1.getString("invoiceSerialNum"); invoiceSettingDTO.setInvoiceId(invoiceSerialNum); System.out.println(json+"========><"); //查询发票开具状态 invoiceSettingDTO.setInvoiceRed("1");//蓝票 getInfoCX(invoiceSettingDTO); map.put("invoiceId",invoiceSerialNum); return map; } } catch (Exception e){ log.error("InvoiceSettingServiceImpl.createFP.error==>{}",e.getMessage()); if(e instanceof XXXException){ throw new XXXException(ErrorCode.SYSTEM_ERROR.getCode(),e.getMessage()); } throw new XXXException(ErrorCode.SYSTEM_ERROR.getCode(),"系统异常,请稍后再试!"); } }
1.相关请求参数
2.响应结果示例:
{ "code": "E0000", "describe": "获取成功", "result": [ { "serialNo": "19010211130401000006", "orderNo": "1001000011161", "status": "2", "statusMsg": "开票完成(最终状态)", "failCause": "", "pdfUrl": "https://invtest.jss.com.cn/group1/M00/0D/A4/wKjScVwsK6CAFzLgAABsVO-OKaE630.pdf", "pictureUrl": "nnfpkf.jss.com.cn/ArQ6dFE3-9o5x4B", "invoiceTime": 1546398919000, "invoiceCode": "131880930142", "invoiceNo": "18757776", "exTaxAmount": "0.38", "taxAmount": "0.02", "payerName": "个人2", "payerTaxNo": "110101TRDX8RQU1", "invoiceKind": "电子增值税普通发票", "checkCode": "72969719882523170140", "invoiceItems": [ { "itemName": "门票", "itemUnit": "张", "itemPrice": "0.300000000000000000", "itemTaxRate": "0.06", "itemNum": "2.000000000000000000", "itemAmount": "0.60", "itemTaxAmount": "0.03", "itemSpec": "", "itemCode": "3070101000000000000", "isIncludeTax": "true", "invoiceLineProperty": "2", "zeroRateFlag": "", "favouredPolicyName": "", "favouredPolicyFlag": "0" }, …… ] }, …… ] }
3.示例代码
public Map<String,Object> getInfo(InvoiceSettingDTO invoiceSettingDTO) { try { Map<String,Object> map = new HashMap<>(); String status =""; String pdfUrl =""; String pictureUrl =""; String invoiceCode ="";//发票代码 String invoiceNo ="";//发票号码 LambdaQueryWrapper<InvoiceInfo> lq1 = new LambdaQueryWrapper<>(); lq1.eq(InvoiceInfo::getOrderId,invoiceSettingDTO.getOrderId()); InvoiceInfo invoiceInfo = invoiceInfoMapper.selectOne(lq1); String senid = UUID.randomUUID().toString().replace("-", ""); // 唯一标识,32位随机码,无需修改,保持默认即可 String method = "nuonuo.ElectronInvoice.queryInvoiceResult"; // API方法名 NNOpenSDK sdk = NNOpenSDK.getIntance(); String token = getToken(); JSONObject jsonObject = new JSONObject(); jsonObject.put("serialNos",invoiceSettingDTO.getInvoiceId()); jsonObject.put("isOfferInvoiceDetail","0"); String content = jsonObject.toJSONString(); log.info("author in ==>"+content); String json = sdk.sendPostSyncRequest(baseURL, senid, aPPKey, aPPSecret, token, taxnum, method, content); log.info("author out ==>"+json); //获取结果json JSONObject result = JSONObject.parseObject(json); String code = result.getString("code"); if (code.equals("E0000")){ //获取结果集 List<InvoiceInfoVO> infoVOS = result.getJSONArray("result").toJavaList(InvoiceInfoVO.class); invoiceSettingDTO.getInvoiceSerialNum(); if (infoVOS.size()>=0){ status = infoVOS.get(0).getStatus(); pdfUrl = infoVOS.get(0).getPdfUrl(); pictureUrl = infoVOS.get(0).getPictureUrl(); invoiceCode = infoVOS.get(0).getInvoiceCode(); invoiceNo = infoVOS.get(0).getInvoiceNo(); String failCause = infoVOS.get(0).getFailCause(); System.out.println(json+"======>>>"); System.out.println(json+"======>>>"); System.out.println(json+"======>>>"); System.out.println(json+"======>>>"); if (ObjectUtil.isNotEmpty(failCause)){ throw new XXXException(failCause+",请稍后再试,或致电010-88545091"); } }else { throw new XXXException("调用查询发票接口失败!"); } map.put("status",status); map.put("pdfUrl",pdfUrl); map.put("pictureUrl",pictureUrl); return map; }else { String errormsg = result.getString("describe"); throw new HbsxException(errormsg+",请稍后再试"); } } catch (Exception e){ log.error("InvoiceSettingServiceImpl.getInfo.error==>{}",e.getMessage()); if(e instanceof XXXException){ throw new XXXException(ErrorCode.SYSTEM_ERROR.getCode(),e.getMessage()); } throw new XXXException(ErrorCode.SYSTEM_ERROR.getCode(),"系统异常,请稍后再试!"); } }
4.返回码说明:
以上就是诺诺发票的自助开票和查询接口的使用,其他冲红等接口与这两个接口调用方式一致,如有侵权,请联系我删除文章,学习之路山高路远,还请各位大佬指正!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。