|
@@ -0,0 +1,778 @@
|
|
|
|
|
+package com.jeeplus.assess.invoice.service.OMS;
|
|
|
|
|
+
|
|
|
|
|
+import com.alibaba.fastjson.JSON;
|
|
|
|
|
+import com.fasterxml.jackson.databind.ObjectMapper;
|
|
|
|
|
+import com.jeeplus.assess.invoice.domain.OMS.OMSAccessTokenInfo;
|
|
|
|
|
+import com.jeeplus.assess.invoice.domain.FinanceInvoiceTaxClassificationCode;
|
|
|
|
|
+import com.jeeplus.assess.invoice.mapper.FinanceInvoiceMapper;
|
|
|
|
|
+import com.jeeplus.assess.invoice.service.FinanceInvoiceService;
|
|
|
|
|
+import com.jeeplus.assess.invoice.service.dto.FinanceInvoiceDTO;
|
|
|
|
|
+import com.jeeplus.assess.invoice.utils.OMS.HttpPostJsonUtil;
|
|
|
|
|
+import com.jeeplus.assess.invoice.utils.OMS.OMSNationUtil;
|
|
|
|
|
+import com.jeeplus.common.redis.RedisUtils;
|
|
|
|
|
+
|
|
|
|
|
+import com.jeeplus.utils.StringUtils;
|
|
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
|
|
+import org.springframework.context.annotation.Lazy;
|
|
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
|
|
+import org.springframework.transaction.annotation.Transactional;
|
|
|
|
|
+
|
|
|
|
|
+import java.util.HashMap;
|
|
|
|
|
+import java.util.Map;
|
|
|
|
|
+import java.util.UUID;
|
|
|
|
|
+import java.util.concurrent.TimeUnit;
|
|
|
|
|
+
|
|
|
|
|
+import static com.jeeplus.assess.invoice.config.FinanceOmsConfig.*;
|
|
|
|
|
+
|
|
|
|
|
+@Service
|
|
|
|
|
+@Transactional(readOnly = true)
|
|
|
|
|
+@Lazy
|
|
|
|
|
+public class OMSDisposeService {
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 给accessToken查询的有效时间设置为1天
|
|
|
|
|
+ */
|
|
|
|
|
+
|
|
|
|
|
+ //如果接口访问不正确,可以循环访问的次数
|
|
|
|
|
+ private final int remainRetryTimes = 20;
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private FinanceInvoiceMapper workInvoiceDao;
|
|
|
|
|
+
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private FinanceInvoiceService workInvoiceService;
|
|
|
|
|
+
|
|
|
|
|
+ // 注入SpringBoot内置的JSON序列化工具(无额外依赖)
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private ObjectMapper objectMapper;
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 用于生成开蓝票信息
|
|
|
|
|
+ * @param map
|
|
|
|
|
+ * @param workInvoiceId 需要开票的开票信息id
|
|
|
|
|
+ */
|
|
|
|
|
+ @Transactional(readOnly = false)
|
|
|
|
|
+ public void doInvoiceBusiness(Map<String,Object> map, String workInvoiceId, String informType) {
|
|
|
|
|
+ RedisUtils jedis = null;
|
|
|
|
|
+ String accessToken = null;
|
|
|
|
|
+ try {
|
|
|
|
|
+ jedis = RedisUtils.getInstance();
|
|
|
|
|
+ accessToken = (String) jedis.get("PGOMSAccessToken");
|
|
|
|
|
+ if(StringUtils.isBlank(accessToken)){
|
|
|
|
|
+ // 获取AccessToken 9998重试5次
|
|
|
|
|
+ accessToken = getOmsAccessTokenWithRetry(10, "accessToken", workInvoiceId, informType);
|
|
|
|
|
+ if(StringUtils.isNotBlank(accessToken)){
|
|
|
|
|
+ jedis.setEx("PGOMSAccessToken", accessToken,86400, TimeUnit.SECONDS);
|
|
|
|
|
+ map.put("token状态", "重新获取token成功,存入Redis");
|
|
|
|
|
+ } else {
|
|
|
|
|
+ accessToken = "";
|
|
|
|
|
+ map.put("token状态", "获取token失败");
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ map.put("token状态", "从Redis获取token成功");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ OMSNationUtil util = new OMSNationUtil();
|
|
|
|
|
+ //获取需要开票的发票信息
|
|
|
|
|
+ FinanceInvoiceDTO workInvoice = workInvoiceService.queryById(workInvoiceId);
|
|
|
|
|
+
|
|
|
|
|
+ if(null != workInvoice){
|
|
|
|
|
+ if( StringUtils.isBlank(workInvoice.getBillingPeopleReal())){
|
|
|
|
|
+ handleInvoiceRetryAllFail("",workInvoiceId, "开票获取发票信息失败", informType); // 解析失败直接兜底
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if(StringUtils.isBlank(workInvoice.getBankAccount())){
|
|
|
|
|
+ handleInvoiceRetryAllFail("",workInvoiceId, "开票获取发票信息失败", informType); // 解析失败直接兜底
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ //判定开票内容是否关联税收编码
|
|
|
|
|
+ if(StringUtils.isNotBlank(workInvoice.getBillingContent())){
|
|
|
|
|
+ FinanceInvoiceTaxClassificationCode billingContentDetail = workInvoiceDao.getBillingContentDetail(workInvoice);
|
|
|
|
|
+ if(null != billingContentDetail){
|
|
|
|
|
+ workInvoice.setBillingContent(billingContentDetail.getGoodName());
|
|
|
|
|
+ workInvoice.setGoodsTaxno(billingContentDetail.getGoodsTaxno());
|
|
|
|
|
+ }else{
|
|
|
|
|
+ handleInvoiceRetryAllFail("",workInvoiceId, "未找到对应税收编码,请联系信息部确认后重新发起", informType); // 解析失败直接兜底
|
|
|
|
|
+ }
|
|
|
|
|
+ //生成开票基础信息
|
|
|
|
|
+ String string = util.neatenData(workInvoiceId,workInvoice,billingContentDetail);
|
|
|
|
|
+
|
|
|
|
|
+ OMSAccessTokenInfo InvoiceTokenInfo = new OMSAccessTokenInfo();
|
|
|
|
|
+ InvoiceTokenInfo.setAppId(appId);
|
|
|
|
|
+ InvoiceTokenInfo.setAppKey(appKey);
|
|
|
|
|
+ InvoiceTokenInfo.setExchangeId(UUID.randomUUID().toString());
|
|
|
|
|
+ InvoiceTokenInfo.setAccessToken(accessToken);
|
|
|
|
|
+ InvoiceTokenInfo.setData(string);
|
|
|
|
|
+ String jsonInvoiceStr = JSON.toJSONString(InvoiceTokenInfo);
|
|
|
|
|
+
|
|
|
|
|
+ String jsonInvoicResultStr = HttpPostJsonUtil.doPost(omsUrl +"/prod-api/output/server/order/upload", jsonInvoiceStr);
|
|
|
|
|
+ System.out.println("✅ 订单提交接口返回值:" + jsonInvoicResultStr);
|
|
|
|
|
+ map.put("订单接口信息", jsonInvoicResultStr);
|
|
|
|
|
+
|
|
|
|
|
+ // 调用订单上传重试方法(包含所有码值规则)
|
|
|
|
|
+ if(StringUtils.isNotBlank(jsonInvoicResultStr)){
|
|
|
|
|
+ //将上个节点获取的值存到数据库,留作redis崩溃后进行重新获取处理
|
|
|
|
|
+ workInvoice.setOrderForGoodsResultStr(jsonInvoicResultStr);
|
|
|
|
|
+ workInvoiceDao.updateOrderForGoodsResultStrById(workInvoice);
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ String finalAccessToken = accessToken;
|
|
|
|
|
+ String finalJsonInvoiceStr = jsonInvoiceStr;
|
|
|
|
|
+ executeOrderUploadRetry(workInvoiceId, remainRetryTimes, jsonInvoicResultStr, finalJsonInvoiceStr, finalAccessToken, map,"accessToken", "blueTicket", informType);
|
|
|
|
|
+ }else{
|
|
|
|
|
+ handleInvoiceRetryAllFail(jsonInvoiceStr,workInvoiceId, "蓝票发送订单生成接口返回值为空,开票失败。节点访问参数为:" + jsonInvoicResultStr, informType); // 解析失败直接兜底
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+ }else{
|
|
|
|
|
+ handleInvoiceRetryAllFail("",workInvoiceId, "开票获取发票信息失败", informType); // 解析失败直接兜底
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ }else{
|
|
|
|
|
+ handleInvoiceRetryAllFail("",workInvoiceId, "开票获取发票信息失败", informType); // 解析失败直接兜底
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ e.printStackTrace();
|
|
|
|
|
+ map.put("errorMsg", "系统异常:" + e.getMessage());
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ if(jedis != null){
|
|
|
|
|
+ //jedis.close();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 用于调用accessToken
|
|
|
|
|
+ * @param remainRetryTimes
|
|
|
|
|
+ * @param getKey
|
|
|
|
|
+ * @return
|
|
|
|
|
+ */
|
|
|
|
|
+ @Transactional(readOnly = false)
|
|
|
|
|
+ public String getOmsAccessTokenWithRetry(int remainRetryTimes, String getKey, String workInvoiceId, String informType) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ OMSAccessTokenInfo tokenInfo = new OMSAccessTokenInfo();
|
|
|
|
|
+ tokenInfo.setAppId(appId);
|
|
|
|
|
+ tokenInfo.setAppKey(appKey);
|
|
|
|
|
+ tokenInfo.setExchangeId(UUID.randomUUID().toString());
|
|
|
|
|
+ String jsonStr = JSON.toJSONString(tokenInfo);
|
|
|
|
|
+ String accessTokenStr = HttpPostJsonUtil.doPost(omsUrl +"/prod-api/server/accessToken", jsonStr);
|
|
|
|
|
+
|
|
|
|
|
+ if(StringUtils.isBlank(accessTokenStr)){
|
|
|
|
|
+ System.err.println("获取AccessToken失败:接口返回空,剩余重试次数:"+remainRetryTimes);
|
|
|
|
|
+ if (remainRetryTimes > 1) {
|
|
|
|
|
+ int nextRetry = remainRetryTimes - 1;
|
|
|
|
|
+ System.err.println("⚠️ 获取AccessToken失败:接口返回空,剩余重试次数:"+nextRetry);
|
|
|
|
|
+ Thread.sleep(30 * 1000);
|
|
|
|
|
+ return getOmsAccessTokenWithRetry(nextRetry, getKey, workInvoiceId, informType);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ System.err.println("❌ 获取AccessToken失败:接口返回空,重试次数耗尽!");
|
|
|
|
|
+ //需要将错误信息保存到对应开票信息表中
|
|
|
|
|
+ FinanceInvoiceDTO workInvoice = workInvoiceService.queryById(workInvoiceId);
|
|
|
|
|
+ if(null != workInvoice){
|
|
|
|
|
+ workInvoice.setOmsAccessTokenError("获取AccessToken失败:接口返回空");
|
|
|
|
|
+ //修改结果
|
|
|
|
|
+ workInvoiceDao.updateAccessTokenErrorById(workInvoice);
|
|
|
|
|
+ }
|
|
|
|
|
+ //如果需要 可以将执行失败信息通过短信通知业务发起人
|
|
|
|
|
+ handleInvoiceRetryAllFail("", workInvoiceId, "获取AccessToken失败:接口返回空", informType); // 解析失败也执行兜底方法
|
|
|
|
|
+
|
|
|
|
|
+ return "";
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ OMSAccessTokenInfo resultTokenInfo = JSON.parseObject(accessTokenStr, OMSAccessTokenInfo.class);
|
|
|
|
|
+ if(null == resultTokenInfo || null == resultTokenInfo.getResult()){
|
|
|
|
|
+ System.err.println("获取AccessToken失败:返回结果解析异常,剩余重试次数:"+remainRetryTimes);
|
|
|
|
|
+ if (remainRetryTimes > 1) {
|
|
|
|
|
+ int nextRetry = remainRetryTimes - 1;
|
|
|
|
|
+ System.err.println("⚠️ 获取AccessToken失败:返回结果解析异常,剩余重试次数:"+nextRetry);
|
|
|
|
|
+ Thread.sleep(30 * 1000);
|
|
|
|
|
+ return getOmsAccessTokenWithRetry(nextRetry, getKey, workInvoiceId, informType);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ System.err.println("❌ 获取AccessToken失败:返回结果解析异常,重试次数耗尽!");
|
|
|
|
|
+ //需要将错误信息保存到对应开票信息表中
|
|
|
|
|
+ FinanceInvoiceDTO workInvoice = workInvoiceService.queryById(workInvoiceId);
|
|
|
|
|
+ if(null != workInvoice){
|
|
|
|
|
+ workInvoice.setOmsAccessTokenError("获取AccessToken失败:返回结果解析异常");
|
|
|
|
|
+ //修改结果
|
|
|
|
|
+ workInvoiceDao.updateAccessTokenErrorById(workInvoice);
|
|
|
|
|
+ }
|
|
|
|
|
+ //如果需要 可以将执行失败信息通过短信通知业务发起人
|
|
|
|
|
+ handleInvoiceRetryAllFail("", workInvoiceId, "获取AccessToken失败:返回结果解析异常", informType); // 解析失败也执行兜底方法
|
|
|
|
|
+
|
|
|
|
|
+ return "";
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ String code = resultTokenInfo.getResult().getCode();
|
|
|
|
|
+ String message = resultTokenInfo.getResult().getMessage();
|
|
|
|
|
+ if ("0000".equals(code)) {
|
|
|
|
|
+ String token = OMSNationUtil.extractAccessTokenFromBase64(getKey, resultTokenInfo.getData().toString());
|
|
|
|
|
+ System.out.println("✅ 获取AccessToken成功,重试次数剩余:"+remainRetryTimes);
|
|
|
|
|
+ return token;
|
|
|
|
|
+ } else if ("9998".equals(code)) {
|
|
|
|
|
+ if (remainRetryTimes > 1) {
|
|
|
|
|
+ int nextRetry = remainRetryTimes - 1;
|
|
|
|
|
+ System.err.println("⚠️ 获取AccessToken返回9998接口波动,30秒后重试,剩余次数:"+nextRetry);
|
|
|
|
|
+ Thread.sleep(30 * 1000);
|
|
|
|
|
+ return getOmsAccessTokenWithRetry(nextRetry, getKey, workInvoiceId, informType);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ System.err.println("❌ 获取AccessToken失败:连续5次返回9998,重试次数耗尽!");
|
|
|
|
|
+ //需要将错误信息保存到对应开票信息表中
|
|
|
|
|
+ FinanceInvoiceDTO workInvoice = workInvoiceService.queryById(workInvoiceId);
|
|
|
|
|
+ if(null != workInvoice){
|
|
|
|
|
+ workInvoice.setOmsAccessTokenError("获取AccessToken失败,需要业务人员重新发起");
|
|
|
|
|
+ //修改结果
|
|
|
|
|
+ workInvoiceDao.updateAccessTokenErrorById(workInvoice);
|
|
|
|
|
+ }
|
|
|
|
|
+ //如果需要 可以将执行失败信息通过短信通知业务发起人
|
|
|
|
|
+ handleInvoiceRetryAllFail("", workInvoiceId, "获取AccessToken失败,需要业务人员重新发起", informType); // 解析失败也执行兜底方法
|
|
|
|
|
+
|
|
|
|
|
+ return "";
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ System.err.println("❌ 获取AccessToken失败:返回业务错误码,code:"+code + "。 错误信息为:"+message);
|
|
|
|
|
+ //需要将错误信息保存到对应开票信息表中
|
|
|
|
|
+ FinanceInvoiceDTO workInvoice = workInvoiceService.queryById(workInvoiceId);
|
|
|
|
|
+ if(null != workInvoice){
|
|
|
|
|
+ workInvoice.setOmsAccessTokenError("获取AccessToken失败:返回业务错误码,code:"+code + "; 错误信息为:"+message + "。需要业务人员重新发起");
|
|
|
|
|
+ //修改结果
|
|
|
|
|
+ workInvoiceDao.updateAccessTokenErrorById(workInvoice);
|
|
|
|
|
+ }
|
|
|
|
|
+ return "";
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (InterruptedException e) {
|
|
|
|
|
+ System.err.println("❌ 获取AccessToken失败:重试延迟被中断");
|
|
|
|
|
+ Thread.currentThread().interrupt();
|
|
|
|
|
+ return "";
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ e.printStackTrace();
|
|
|
|
|
+ System.err.println("❌ 获取AccessToken失败:调用接口异常,剩余重试次数:"+remainRetryTimes);
|
|
|
|
|
+ return "";
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 调用订单上传方法,用于执行开票处理
|
|
|
|
|
+ * @param workInvoiceId 发票id
|
|
|
|
|
+ * @param remainRetryTimes 允许接口重调次数
|
|
|
|
|
+ * @param jsonInvoicResultStr 上一个接口返回值
|
|
|
|
|
+ * @param jsonInvoiceStr 上一个接口参数值
|
|
|
|
|
+ * @param accessToken 接口访问accessToken
|
|
|
|
|
+ * @param map 作用不大,仅作为保留
|
|
|
|
|
+ * @param getKey 用来判定的参数值
|
|
|
|
|
+ * @param initiationType 用来判定是什么类型的,比如蓝票、全类型红票、还是快捷红票
|
|
|
|
|
+ * @param informType 流程用来通知的类型
|
|
|
|
|
+ */
|
|
|
|
|
+
|
|
|
|
|
+ @Transactional(readOnly = false)
|
|
|
|
|
+ public void executeOrderUploadRetry(String workInvoiceId, int remainRetryTimes, String jsonInvoicResultStr, String jsonInvoiceStr, String accessToken, Map<String,Object> map, String getKey, String initiationType, String informType) {
|
|
|
|
|
+ String jsonInvoicResult = "";
|
|
|
|
|
+ try {
|
|
|
|
|
+ OMSAccessTokenInfo resultTokenInfo = JSON.parseObject(jsonInvoicResultStr, OMSAccessTokenInfo.class);
|
|
|
|
|
+ if(null == resultTokenInfo || null == resultTokenInfo.getResult()){
|
|
|
|
|
+ System.err.println("❌ 订单上传解析失败,剩余重试次数:"+remainRetryTimes);
|
|
|
|
|
+ handleInvoiceRetryAllFail(accessToken, workInvoiceId, "", informType); // 解析失败也执行兜底方法
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ String code = resultTokenInfo.getResult().getCode();
|
|
|
|
|
+ String message = resultTokenInfo.getResult().getMessage();
|
|
|
|
|
+
|
|
|
|
|
+ // ======================== 所有码值规则 全部在这里【最终定稿】=========================
|
|
|
|
|
+ if ("0000".equals(code)) {
|
|
|
|
|
+ // ✅ 0000 成功:解析数据+存入map+触发30秒后异步下载发票
|
|
|
|
|
+ jsonInvoicResult = OMSNationUtil.extractAccessTokenFromBase64(getKey, resultTokenInfo.getData().toString());
|
|
|
|
|
+ map.put("订单接口返回值",jsonInvoicResult);
|
|
|
|
|
+ System.out.println("✅ 订单上传返回0000成功,触发发票下载接口");
|
|
|
|
|
+ if(StringUtils.isNotBlank(jsonInvoicResult)){
|
|
|
|
|
+ if(initiationType.equals("fastRed")){
|
|
|
|
|
+ workInvoiceId = jsonInvoicResult;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ String finalWorkInvoiceId = workInvoiceId;
|
|
|
|
|
+ // 存入Redis,由InvoiceDownloadTask接管
|
|
|
|
|
+ saveInvoiceDownloadTaskToRedis(accessToken, finalWorkInvoiceId, informType);
|
|
|
|
|
+ System.out.println("✅ 解析开票数据任务["+finalWorkInvoiceId+"]已存入Redis,由InvoiceDownloadTask接管重试");
|
|
|
|
|
+
|
|
|
|
|
+ } else if ("9998".equals(code)) {
|
|
|
|
|
+ // 通过redis调用 方式系统崩溃导致的数据丢失
|
|
|
|
|
+ // ✅ 9998 接口波动,放入redis中 用于定时任务进行处理
|
|
|
|
|
+ saveInvoiceRetryScheduledTaskToRedis(jsonInvoiceStr, accessToken, workInvoiceId, getKey, initiationType);
|
|
|
|
|
+
|
|
|
|
|
+ } else if ("0003".equals(code)) {
|
|
|
|
|
+ // ✅ 0003 token失效:清除旧token → 重新获取token → 从头完整执行所有流程
|
|
|
|
|
+ System.err.println("⚠️ 订单上传返回0003(token失效),开始重新获取token并从头执行流程");
|
|
|
|
|
+ RedisUtils jedis = null;
|
|
|
|
|
+ try {
|
|
|
|
|
+ jedis = RedisUtils.getInstance();
|
|
|
|
|
+ jedis.delete("PGOMSAccessToken");
|
|
|
|
|
+ map.put("0003处理", "已清除旧token,准备重新获取");
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ e.printStackTrace();
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ if(jedis != null) {
|
|
|
|
|
+ //jedis.close();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ doInvoiceBusiness(map, workInvoiceId, informType);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // ✅ ✅ ✅ 核心修正:0001/0002/其他任意错误码 → 直接调用handleInvoiceRetryAllFail执行修改系统信息逻辑 ✅ ✅ ✅
|
|
|
|
|
+ System.err.println("❌ 订单上传返回业务错误码:"+code+",立即执行失败兜底逻辑修改系统信息!");
|
|
|
|
|
+ System.err.println("❌ 订单上传返回业务错误原因:"+message);
|
|
|
|
|
+ map.put("订单状态", "失败,错误码:"+code);
|
|
|
|
|
+ handleInvoiceRetryAllFail(accessToken, workInvoiceId, "订单上传返回业务错误码:"+code+",错误原因:"+message, informType); // 解析失败也执行兜底方法
|
|
|
|
|
+ remainRetryTimes = 0;
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ e.printStackTrace();
|
|
|
|
|
+ System.err.println("❌ 订单上传重试异常,剩余次数:"+remainRetryTimes);
|
|
|
|
|
+ handleInvoiceRetryAllFail(accessToken, workInvoiceId, "订单上传重试异常,请重新发起", informType); // 解析失败也执行兜底方法
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 用于访问接口返回9998时使用,存入Redis供定时任务处理
|
|
|
|
|
+ * 硬编码配置:初始重试次数100次,Redis过期时间1天(86400秒)
|
|
|
|
|
+ * @param jsonInvoiceStr 订单上传的JSON参数
|
|
|
|
|
+ * @param accessToken AccessToken
|
|
|
|
|
+ * @param workInvoiceId 订单号
|
|
|
|
|
+ * @param getKey 获取token的key
|
|
|
|
|
+ * @param initiationType 开票类型(蓝票/红票)
|
|
|
|
|
+ */
|
|
|
|
|
+ @Transactional(readOnly = false)
|
|
|
|
|
+ public void saveInvoiceRetryScheduledTaskToRedis(String jsonInvoiceStr ,String accessToken, String workInvoiceId, String getKey, String initiationType) {
|
|
|
|
|
+ RedisUtils jedis = null;
|
|
|
|
|
+ // 硬编码:初始重试次数100次
|
|
|
|
|
+ final int INIT_RETRY_COUNT = 100;
|
|
|
|
|
+ // 硬编码:Redis任务过期时间1天(86400秒)
|
|
|
|
|
+ final int REDIS_EXPIRE_SECONDS = 86400;
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ jedis = RedisUtils.getInstance();
|
|
|
|
|
+ String redisKey = "PG_OMS_invoice_retry_scheduled:" + workInvoiceId;
|
|
|
|
|
+
|
|
|
|
|
+ // 先检查是否已存在,存在则复用原有重试次数,不存在则初始化20次
|
|
|
|
|
+ String retryTimes = (String) jedis.hGet(redisKey, "retryTimes");
|
|
|
|
|
+ if (StringUtils.isBlank(retryTimes)) {
|
|
|
|
|
+ retryTimes = String.valueOf(INIT_RETRY_COUNT); // 初始20次
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 存储所有需要的字段
|
|
|
|
|
+ jedis.hPut(redisKey, "jsonInvoiceStr", jsonInvoiceStr);
|
|
|
|
|
+ jedis.hPut(redisKey, "accessToken", accessToken);
|
|
|
|
|
+ jedis.hPut(redisKey, "workInvoiceId", workInvoiceId);
|
|
|
|
|
+ jedis.hPut(redisKey, "getKey", getKey);
|
|
|
|
|
+ jedis.hPut(redisKey, "initiationType", initiationType);
|
|
|
|
|
+ jedis.hPut(redisKey, "firstExecTime", String.valueOf(System.currentTimeMillis()));
|
|
|
|
|
+ jedis.hPut(redisKey, "retryTimes", retryTimes); // 重试次数
|
|
|
|
|
+
|
|
|
|
|
+ jedis.expire(redisKey, REDIS_EXPIRE_SECONDS); // 1天过期
|
|
|
|
|
+ System.out.println("✅ 9998重试任务已存入Redis,订单号:" + workInvoiceId + ",剩余重试次数:" + retryTimes);
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ // ========== 追加:Redis数据转JSON,持久化到发票表(兜底逻辑) ==========
|
|
|
|
|
+ long redisStoreTime = System.currentTimeMillis() / 1000; // 秒级存储时间,用于后期回滚
|
|
|
|
|
+ // 封装Map:包含Redis所有哈希字段 + redisKey/过期时间/存储时间,保留redisKey(按你要求)
|
|
|
|
|
+ Map<String, Object> retryTaskMap = new HashMap<>(12);
|
|
|
|
|
+ // Redis哈希中所有原字段(和Redis完全一致)
|
|
|
|
|
+ retryTaskMap.put("jsonInvoiceStr", jsonInvoiceStr);
|
|
|
|
|
+ retryTaskMap.put("accessToken", accessToken);
|
|
|
|
|
+ retryTaskMap.put("workInvoiceId", workInvoiceId);
|
|
|
|
|
+ retryTaskMap.put("getKey", getKey);
|
|
|
|
|
+ retryTaskMap.put("initiationType", initiationType);
|
|
|
|
|
+ retryTaskMap.put("firstExecTime", String.valueOf(System.currentTimeMillis()));
|
|
|
|
|
+ retryTaskMap.put("retryTimes", retryTimes);
|
|
|
|
|
+ // 额外兜底字段(保留redisKey)
|
|
|
|
|
+ retryTaskMap.put("redisKey", redisKey);
|
|
|
|
|
+ retryTaskMap.put("redisExpireSeconds", REDIS_EXPIRE_SECONDS);
|
|
|
|
|
+ retryTaskMap.put("redisStoreTime", redisStoreTime);
|
|
|
|
|
+ retryTaskMap.put("initRetryCount", INIT_RETRY_COUNT); // 追加初始重试次数,后期回滚可参考
|
|
|
|
|
+
|
|
|
|
|
+ // Map转JSON字符串(单独捕获序列化异常,不影响Redis核心逻辑)
|
|
|
|
|
+ String retryTaskJson = objectMapper.writeValueAsString(retryTaskMap);
|
|
|
|
|
+
|
|
|
|
|
+ // 更新发票表(和之前红冲/下载任务用相同的DAO和实体,风格统一)
|
|
|
|
|
+ FinanceInvoiceDTO workInvoice = new FinanceInvoiceDTO();
|
|
|
|
|
+ workInvoice.setId(workInvoiceId);
|
|
|
|
|
+ workInvoice.setRetryInvoiceJson(retryTaskJson);
|
|
|
|
|
+ // 处理DAO更新结果,按你的风格打印控制台信息
|
|
|
|
|
+ workInvoiceDao.updateRedInvoiceJsonByWorkInvoiceId(workInvoice);
|
|
|
|
|
+
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ e.printStackTrace();
|
|
|
|
|
+ System.err.println("❌ 存入9998重试任务到Redis失败,订单号:" + workInvoiceId + ",原因:" + e.getMessage());
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ if (jedis != null) {
|
|
|
|
|
+ //jedis.close();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 新增开蓝票生成的下载用的redis
|
|
|
|
|
+ * @param accessToken
|
|
|
|
|
+ * @param workInvoiceId 开票的id
|
|
|
|
|
+ */
|
|
|
|
|
+ public void saveInvoiceDownloadTaskToRedis(String accessToken, String workInvoiceId, String informType) {
|
|
|
|
|
+ RedisUtils jedis = null;
|
|
|
|
|
+ try {
|
|
|
|
|
+ jedis = RedisUtils.getInstance();
|
|
|
|
|
+ String redisKey = "PG_OMS_invoice_download:" + workInvoiceId;
|
|
|
|
|
+ jedis.hPut(redisKey, "accessToken", accessToken);
|
|
|
|
|
+ jedis.hPut(redisKey, "workInvoiceId", workInvoiceId);
|
|
|
|
|
+ jedis.hPut(redisKey, "informType", informType);
|
|
|
|
|
+ jedis.hPut(redisKey, "firstExecTime", String.valueOf(System.currentTimeMillis()));
|
|
|
|
|
+ jedis.expire(redisKey, 7200); // 1天过期
|
|
|
|
|
+
|
|
|
|
|
+ // ========== 追加:封装Redis数据→转JSON→更新发票表(和红冲方法逻辑一致) ==========
|
|
|
|
|
+ long redisStoreTime = System.currentTimeMillis() / 1000; // 秒级存储时间,用于后期回滚
|
|
|
|
|
+ // 封装Map:和Redis中存储的键值完全一致,方便后期回滚解析
|
|
|
|
|
+ Map<String, Object> downloadTaskMap = new HashMap<>(10);
|
|
|
|
|
+ downloadTaskMap.put("accessToken", accessToken);
|
|
|
|
|
+ downloadTaskMap.put("workInvoiceId", workInvoiceId);
|
|
|
|
|
+ downloadTaskMap.put("informType", informType);
|
|
|
|
|
+ downloadTaskMap.put("firstExecTime", String.valueOf(System.currentTimeMillis())); // 和Redis保持一致的毫秒数字符串
|
|
|
|
|
+ downloadTaskMap.put("redisKey", redisKey);
|
|
|
|
|
+ downloadTaskMap.put("redisExpireSeconds", 7200);
|
|
|
|
|
+ downloadTaskMap.put("redisStoreTime", redisStoreTime); // 新增秒级存储时间
|
|
|
|
|
+
|
|
|
|
|
+ // Map转JSON字符串(单独捕获序列化异常,不影响核心逻辑)
|
|
|
|
|
+ String downloadTaskJson = objectMapper.writeValueAsString(downloadTaskMap);
|
|
|
|
|
+
|
|
|
|
|
+ // 更新发票表(和红冲方法用相同的DAO/实体,保持风格统一)
|
|
|
|
|
+ FinanceInvoiceDTO workInvoice = new FinanceInvoiceDTO();
|
|
|
|
|
+ workInvoice.setId(workInvoiceId);
|
|
|
|
|
+ workInvoice.setBlueDownloadInvoiceJson(downloadTaskJson);
|
|
|
|
|
+ workInvoiceDao.updateRedInvoiceJsonByWorkInvoiceId(workInvoice);
|
|
|
|
|
+
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ e.printStackTrace();
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ if (jedis != null) {
|
|
|
|
|
+ //jedis.close();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 兜底方法
|
|
|
|
|
+ * @param accessToken
|
|
|
|
|
+ */
|
|
|
|
|
+ @Transactional(readOnly = false)
|
|
|
|
|
+ public void handleInvoiceRetryAllFail(String accessToken, String workInvoiceId, String errorMessage, String informType) {
|
|
|
|
|
+ // ============ 你的所有【修改系统信息/更新订单状态/写失败日志】逻辑 全部写在这里!!! ============
|
|
|
|
|
+ try {
|
|
|
|
|
+ System.err.println("============ 开始执行【失败兜底-系统信息修改逻辑】 ============");
|
|
|
|
|
+ FinanceInvoiceDTO workInvoice = workInvoiceService.queryById(workInvoiceId);
|
|
|
|
|
+ if(null != workInvoice){
|
|
|
|
|
+ //将错误信息保存到数据库
|
|
|
|
|
+ workInvoice.setOmsErrorMessage(errorMessage);
|
|
|
|
|
+ workInvoice.setOmsAccessToken(accessToken);
|
|
|
|
|
+ workInvoice.setStatus("3");
|
|
|
|
|
+ //修改结果
|
|
|
|
|
+ workInvoiceDao.updateAccessTokenErrorById(workInvoice);
|
|
|
|
|
+
|
|
|
|
|
+ //通知发起人或者开票管理员
|
|
|
|
|
+ workInvoiceService.handleInvoiceRetryAllFail(workInvoice, errorMessage, informType);
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ System.err.println("============ 【失败兜底-系统信息修改逻辑】执行完成 ============");
|
|
|
|
|
+
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ // 必加:捕获这个方法的异常,避免兜底方法报错导致线程异常
|
|
|
|
|
+ e.printStackTrace();
|
|
|
|
|
+ System.err.println("❌ 执行失败兜底方法时抛出异常:" + e.getMessage());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 快速开红票的调用方法
|
|
|
|
|
+ * @param map
|
|
|
|
|
+ * @param allEinvno
|
|
|
|
|
+ */
|
|
|
|
|
+ @Transactional(readOnly = false)
|
|
|
|
|
+ public void doFastRedInvoiceBusiness(Map<String,Object> map, String allEinvno, String workInvoiceId, String informType) {
|
|
|
|
|
+ RedisUtils jedis = null;
|
|
|
|
|
+ String accessToken = null;
|
|
|
|
|
+ try {
|
|
|
|
|
+ jedis = RedisUtils.getInstance();
|
|
|
|
|
+ accessToken = (String) jedis.get("PGOMSAccessToken");
|
|
|
|
|
+ if(StringUtils.isBlank(accessToken)){
|
|
|
|
|
+ // 获取AccessToken 9998重试5次
|
|
|
|
|
+ accessToken = getOmsAccessTokenWithRetry(10, "accessToken", workInvoiceId, informType);
|
|
|
|
|
+ if(StringUtils.isNotBlank(accessToken)){
|
|
|
|
|
+ jedis.setEx("PGOMSAccessToken", accessToken,86400,TimeUnit.SECONDS);
|
|
|
|
|
+ map.put("token状态", "重新获取token成功,存入Redis");
|
|
|
|
|
+ } else {
|
|
|
|
|
+ accessToken = "";
|
|
|
|
|
+ map.put("token状态", "获取token失败");
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ map.put("token状态", "从Redis获取token成功");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ OMSNationUtil util = new OMSNationUtil();
|
|
|
|
|
+ String string = util.neatenFastRedInvoiceData(allEinvno);
|
|
|
|
|
+
|
|
|
|
|
+ OMSAccessTokenInfo InvoiceTokenInfo = new OMSAccessTokenInfo();
|
|
|
|
|
+ InvoiceTokenInfo.setAppId(appId);
|
|
|
|
|
+ InvoiceTokenInfo.setAppKey(appKey);
|
|
|
|
|
+ InvoiceTokenInfo.setExchangeId(UUID.randomUUID().toString());
|
|
|
|
|
+ InvoiceTokenInfo.setAccessToken(accessToken);
|
|
|
|
|
+ InvoiceTokenInfo.setData(string);
|
|
|
|
|
+ String jsonInvoiceStr = JSON.toJSONString(InvoiceTokenInfo);
|
|
|
|
|
+
|
|
|
|
|
+ String jsonInvoicResultStr = HttpPostJsonUtil.doPost(omsUrl +"/prod-api/output/server/invoice/makeredinv", jsonInvoiceStr);
|
|
|
|
|
+ System.out.println("✅ 快速红冲订单提交接口返回值:" + jsonInvoicResultStr);
|
|
|
|
|
+ map.put("快速红冲订单接口信息", jsonInvoicResultStr);
|
|
|
|
|
+
|
|
|
|
|
+ // 调用订单上传重试方法(包含所有码值规则)
|
|
|
|
|
+ if(StringUtils.isNotBlank(jsonInvoicResultStr)){
|
|
|
|
|
+ String finalAccessToken = accessToken;
|
|
|
|
|
+ String finalJsonInvoiceStr = jsonInvoiceStr;
|
|
|
|
|
+ executeOrderUploadRetry(workInvoiceId, 5, jsonInvoicResultStr, finalJsonInvoiceStr, finalAccessToken, map, "orderno", "fastRed", informType);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ e.printStackTrace();
|
|
|
|
|
+ map.put("errorMsg", "系统异常:" + e.getMessage());
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ if(jedis != null){
|
|
|
|
|
+ //jedis.close();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 调用生成红字确认申请单
|
|
|
|
|
+ * @param map
|
|
|
|
|
+ * @param workInvoiceId 需要开红字票的开票id信息
|
|
|
|
|
+ * @param redInvoiceRelevancyId 开红票对应蓝票的invoiceid
|
|
|
|
|
+ * @param originalInvno 原蓝票发票号码(数电票号码)
|
|
|
|
|
+ * @param informType 用于流程通知的判定条件
|
|
|
|
|
+ */
|
|
|
|
|
+ @Transactional(readOnly = false)
|
|
|
|
|
+ public void doAllScenarioRedInvoiceBusiness(Map<String,Object> map, String workInvoiceId, String redInvoiceRelevancyId, String originalInvno, String informType) {
|
|
|
|
|
+ RedisUtils jedis = null;
|
|
|
|
|
+ String accessToken = null;
|
|
|
|
|
+ try {
|
|
|
|
|
+ jedis = RedisUtils.getInstance();
|
|
|
|
|
+ accessToken = (String)jedis.get("PGOMSAccessToken");
|
|
|
|
|
+ if(StringUtils.isBlank(accessToken)){
|
|
|
|
|
+ // 获取AccessToken 9998重试5次
|
|
|
|
|
+ accessToken = getOmsAccessTokenWithRetry(10, "accessToken", workInvoiceId, informType);
|
|
|
|
|
+ if(StringUtils.isNotBlank(accessToken)){
|
|
|
|
|
+ jedis.setEx("PGOMSAccessToken", accessToken,86400,TimeUnit.SECONDS);
|
|
|
|
|
+ map.put("token状态", "重新获取token成功,存入Redis");
|
|
|
|
|
+ } else {
|
|
|
|
|
+ accessToken = "";
|
|
|
|
|
+ map.put("token状态", "获取token失败");
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ map.put("token状态", "从Redis获取token成功");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ OMSNationUtil util = new OMSNationUtil();
|
|
|
|
|
+ //获取需要开票的发票信息
|
|
|
|
|
+ FinanceInvoiceDTO workInvoice = workInvoiceService.queryById(workInvoiceId);
|
|
|
|
|
+
|
|
|
|
|
+ if(null != workInvoice){
|
|
|
|
|
+
|
|
|
|
|
+ if(StringUtils.isBlank(workInvoice.getBillingPeopleReal()) ){
|
|
|
|
|
+ handleInvoiceRetryAllFail("",workInvoiceId, "开票获取发票信息失败", informType); // 解析失败直接兜底
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ //获取开票银行信息
|
|
|
|
|
+ if(StringUtils.isBlank(workInvoice.getBankAccount())){
|
|
|
|
|
+ handleInvoiceRetryAllFail("",workInvoiceId, "开票获取发票信息失败", informType); // 解析失败直接兜底
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ //获取被红冲发票的基本信息
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ if(StringUtils.isNotBlank(workInvoice.getBillingContent())){
|
|
|
|
|
+ FinanceInvoiceTaxClassificationCode billingContentDetail = workInvoiceDao.getBillingContentDetail(workInvoice);
|
|
|
|
|
+ if(null != billingContentDetail){
|
|
|
|
|
+ workInvoice.setBillingContent(billingContentDetail.getGoodName());
|
|
|
|
|
+ workInvoice.setGoodsTaxno(billingContentDetail.getGoodsTaxno());
|
|
|
|
|
+ }else{
|
|
|
|
|
+ handleInvoiceRetryAllFail("",workInvoiceId, "未找到对应税收编码,请联系信息部确认后重新发起", informType); // 解析失败直接兜底
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ //获取本次红冲对应蓝票的基本信息
|
|
|
|
|
+ FinanceInvoiceDTO workInvoiceRelevancy = workInvoiceService.queryById(redInvoiceRelevancyId);
|
|
|
|
|
+ if(null == workInvoiceRelevancy || null == workInvoiceRelevancy.getBillingPeopleReal()){
|
|
|
|
|
+ handleInvoiceRetryAllFail("",workInvoiceId, "未找到需要红冲票的信息,请确认后重新发起", informType); // 解析失败直接兜底
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ //获取被红冲蓝票的税率信息
|
|
|
|
|
+ FinanceInvoiceTaxClassificationCode relevancyBillingContentDetail = workInvoiceDao.getBillingContentDetail(workInvoiceRelevancy);
|
|
|
|
|
+ if(null == relevancyBillingContentDetail){
|
|
|
|
|
+ handleInvoiceRetryAllFail("",workInvoiceId, "未找到被红冲蓝票的对应税收编码,请联系信息部确认后重新发起", informType); // 解析失败直接兜底
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ //生成红冲的数据
|
|
|
|
|
+ String string = util.neatenAllScenarioRedInvoiceData(workInvoiceId, originalInvno,workInvoice, workInvoiceRelevancy, billingContentDetail,relevancyBillingContentDetail);
|
|
|
|
|
+
|
|
|
|
|
+ OMSAccessTokenInfo InvoiceTokenInfo = new OMSAccessTokenInfo();
|
|
|
|
|
+ InvoiceTokenInfo.setAppId(appId);
|
|
|
|
|
+ InvoiceTokenInfo.setAppKey(appKey);
|
|
|
|
|
+ InvoiceTokenInfo.setExchangeId(UUID.randomUUID().toString());
|
|
|
|
|
+ InvoiceTokenInfo.setAccessToken(accessToken);
|
|
|
|
|
+ InvoiceTokenInfo.setData(string);
|
|
|
|
|
+ String jsonInvoiceStr = JSON.toJSONString(InvoiceTokenInfo);
|
|
|
|
|
+
|
|
|
|
|
+ String jsonInvoicResultStr = HttpPostJsonUtil.doPost(omsUrl +"/prod-api/output/server/redApply/apply", jsonInvoiceStr);
|
|
|
|
|
+ System.out.println("✅ 全场景红冲订单提交接口返回值:" + jsonInvoicResultStr);
|
|
|
|
|
+ map.put("全场景红冲订单接口信息", jsonInvoicResultStr);
|
|
|
|
|
+
|
|
|
|
|
+ // 调用订单上传重试方法(包含所有码值规则)
|
|
|
|
|
+ if(StringUtils.isNotBlank(jsonInvoicResultStr)){
|
|
|
|
|
+
|
|
|
|
|
+ //将上个节点获取的值存到数据库,留作redis崩溃后进行重新获取处理
|
|
|
|
|
+ workInvoice.setOrderForGoodsResultStr(jsonInvoicResultStr);
|
|
|
|
|
+ workInvoiceDao.updateOrderForGoodsResultStrById(workInvoice);
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ String finalAccessToken = accessToken;
|
|
|
|
|
+ queryRedInvoiceConfirm (workInvoiceId, 5, jsonInvoicResultStr, finalAccessToken,informType);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ handleInvoiceRetryAllFail(accessToken,workInvoiceId, "全场景红冲订单接口返回值为空,开票失败。节点申请参数为:"+ jsonInvoiceStr, informType); // 解析失败直接兜底
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ }else{
|
|
|
|
|
+ handleInvoiceRetryAllFail("",workInvoiceId, "开票获取发票信息失败", informType); // 解析失败直接兜底
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ }else{
|
|
|
|
|
+ handleInvoiceRetryAllFail("",workInvoiceId, "开票获取发票信息失败", informType); // 解析失败直接兜底
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ e.printStackTrace();
|
|
|
|
|
+ map.put("errorMsg", "系统异常:" + e.getMessage());
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ if(jedis != null){
|
|
|
|
|
+ //jedis.close();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 全类型红冲--红字确认单查询接口(仅存Redis,不执行业务)
|
|
|
|
|
+ * @param remainRetryTimes 剩余重试次数
|
|
|
|
|
+ * @param jsonInvoicResultStr 需要解析的返回值密文
|
|
|
|
|
+ * @param accessToken accessToken
|
|
|
|
|
+ * @param workInvoiceId 开票的id
|
|
|
|
|
+ */
|
|
|
|
|
+ @Transactional(readOnly = false)
|
|
|
|
|
+ public void queryRedInvoiceConfirm (String workInvoiceId, int remainRetryTimes, String jsonInvoicResultStr, String accessToken, String informType) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ OMSAccessTokenInfo resultTokenInfo = JSON.parseObject(jsonInvoicResultStr, OMSAccessTokenInfo.class);
|
|
|
|
|
+ if(null == resultTokenInfo || null == resultTokenInfo.getResult()){
|
|
|
|
|
+ System.err.println("❌ 全场景红冲订单提交接口返回值解析失败,剩余重试次数:"+remainRetryTimes);
|
|
|
|
|
+ handleInvoiceRetryAllFail(accessToken, workInvoiceId, "", informType); // 解析失败也执行兜底方法
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ String code = resultTokenInfo.getResult().getCode();
|
|
|
|
|
+
|
|
|
|
|
+ if ("0000".equals(code)) {
|
|
|
|
|
+ // 仅存入Redis,删除所有业务执行逻辑
|
|
|
|
|
+ saveRedInvoiceTaskToRedis(workInvoiceId, remainRetryTimes, jsonInvoicResultStr, accessToken, workInvoiceId, System.currentTimeMillis(),informType);
|
|
|
|
|
+ System.out.println("✅ 红冲任务["+workInvoiceId+"]已存入Redis,由定时任务接管执行");
|
|
|
|
|
+ } else {
|
|
|
|
|
+ String message = resultTokenInfo.getResult().getMessage();
|
|
|
|
|
+ System.err.println("❌ 全类型红冲--红字确认单查询接口返回业务错误码:"+code+",错误原因为:"+message);
|
|
|
|
|
+ handleInvoiceRetryAllFail(accessToken, workInvoiceId, "全类型红冲--红字确认单查询接口返回业务错误码:"+code+",错误原因为:"+message, informType); // 解析失败也执行兜底方法
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ e.printStackTrace();
|
|
|
|
|
+ handleInvoiceRetryAllFail(accessToken, workInvoiceId, "全类型红冲--红字确认单查询接口发起失败,请重新发起", informType); // 解析失败也执行兜底方法
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 存储红冲任务到Redis(供原有业务代码调用,参数完整)
|
|
|
|
|
+ * @param workInvoiceId 发票id
|
|
|
|
|
+ * @param remainRetryTimes 允许回调的次数,这里暂时未用到,仅作为保留参数
|
|
|
|
|
+ * @param jsonInvoicResultStr 全场景红冲订单提交接口返回值
|
|
|
|
|
+ * @param accessToken
|
|
|
|
|
+ * @param applyNo 发票id
|
|
|
|
|
+ * @param startTime 这个任务开始时间。限制:开始3天内如果双方没有全部确认,则本次红冲失败
|
|
|
|
|
+ */
|
|
|
|
|
+ @Transactional(readOnly = false)
|
|
|
|
|
+ public void saveRedInvoiceTaskToRedis(String workInvoiceId, int remainRetryTimes, String jsonInvoicResultStr, String accessToken, String applyNo, long startTime, String informType) {
|
|
|
|
|
+ RedisUtils jedis = null;
|
|
|
|
|
+ try {
|
|
|
|
|
+ jedis = RedisUtils.getInstance();
|
|
|
|
|
+ String redisKey = "PG_OMS_red_invoice_task:" + workInvoiceId;
|
|
|
|
|
+ // 存储所有执行所需的参数(确保定时任务能独立执行)
|
|
|
|
|
+ jedis.hPut(redisKey, "remainRetryTimes", String.valueOf(remainRetryTimes));
|
|
|
|
|
+ jedis.hPut(redisKey, "jsonInvoicResultStr", jsonInvoicResultStr);
|
|
|
|
|
+ jedis.hPut(redisKey, "accessToken", accessToken);
|
|
|
|
|
+ jedis.hPut(redisKey, "workInvoiceId", workInvoiceId);
|
|
|
|
|
+ jedis.hPut(redisKey, "informType", informType);
|
|
|
|
|
+ jedis.hPut(redisKey, "startTime", String.valueOf(startTime));
|
|
|
|
|
+ jedis.expire(redisKey, 259200 + 3600); // 3天+1小时过期
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ //将对应的redis中数据进行存储到数据库中,放置redis数据崩溃丢失
|
|
|
|
|
+ // 1. 封装Redis中所有存储的参数到Map(和Redis键值完全一致,方便后期回滚解析)
|
|
|
|
|
+ long redisStoreTime = System.currentTimeMillis() / 1000; // 核心:精确到秒,long类型
|
|
|
|
|
+ Map<String, Object> redInvoiceMap = new HashMap<>(); // 容量从8改为10,适配新字段
|
|
|
|
|
+ redInvoiceMap.put("remainRetryTimes", remainRetryTimes);
|
|
|
|
|
+ redInvoiceMap.put("jsonInvoicResultStr", jsonInvoicResultStr);
|
|
|
|
|
+ redInvoiceMap.put("accessToken", accessToken);
|
|
|
|
|
+ redInvoiceMap.put("workInvoiceId", workInvoiceId);
|
|
|
|
|
+ redInvoiceMap.put("informType", informType);
|
|
|
|
|
+ redInvoiceMap.put("startTime", startTime);
|
|
|
|
|
+ redInvoiceMap.put("redisKey", redisKey);
|
|
|
|
|
+ redInvoiceMap.put("redisExpireSeconds", 259200 + 3600);
|
|
|
|
|
+ redInvoiceMap.put("redisStoreTime", redisStoreTime); // 新增:Redis存储时间(秒级时间戳)
|
|
|
|
|
+
|
|
|
|
|
+ // 2. Map转JSON字符串(Spring内置Jackson,无额外依赖)
|
|
|
|
|
+ String redInvoiceJson = objectMapper.writeValueAsString(redInvoiceMap);
|
|
|
|
|
+
|
|
|
|
|
+ FinanceInvoiceDTO workInvoice = new FinanceInvoiceDTO();
|
|
|
|
|
+ workInvoice.setId(workInvoiceId);
|
|
|
|
|
+ workInvoice.setRedInvoiceJson(redInvoiceJson);
|
|
|
|
|
+ // 3. 更新现有发票表的JSON字段(根据发票ID精准更新)
|
|
|
|
|
+ workInvoiceDao.updateRedInvoiceJsonByWorkInvoiceId(workInvoice);
|
|
|
|
|
+
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ e.printStackTrace();
|
|
|
|
|
+ handleInvoiceRetryAllFail(accessToken, workInvoiceId, "全类型红冲--红字确认单查询接口发起失败,请重新发起", informType); // 解析失败也执行兜底方法
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ if (jedis != null) {
|
|
|
|
|
+ //jedis.close();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+}
|