Browse Source

OMS发票信息部分代码上传

徐滕 1 month ago
parent
commit
c4424a6cc3

+ 7 - 0
src/main/java/com/jeeplus/modules/workinvoice/dao/WorkInvoiceDao.java

@@ -273,4 +273,11 @@ public interface WorkInvoiceDao extends CrudDao<WorkInvoice> {
 	 * @return
 	 */
 	WorkInvoiceTaxClassificationCode getBillingContentDetail(WorkInvoice workInvoice);
+
+	/**
+	 * 修改开票信息对应个节点redis保存的数据
+	 * @param workInvoice
+	 * @return
+	 */
+	Integer updateRedInvoiceJsonByWorkInvoiceId(WorkInvoice workInvoice);
 }

+ 37 - 0
src/main/java/com/jeeplus/modules/workinvoice/entity/WorkInvoice.java

@@ -157,6 +157,11 @@ public class WorkInvoice extends ActEntity<WorkInvoice> {
 
 	private String omsAttachmentUrl;//附件url
 
+	private String redInvoiceJson;//将对应的红冲redis中数据进行存储到数据库中,放置redis数据崩溃丢失
+	private String blueDownloadInvoiceJson;//将对应的蓝票redis中数据进行存储到数据库中,放置redis数据崩溃丢失
+	private String retryInvoiceJson;//将对应的9998错误redis中数据进行存储到数据库中,放置redis数据崩溃丢失
+	private String redDownloadInvoiceJson;//将对应的红票redis中数据进行存储到数据库中,放置redis数据崩溃丢失
+
 
 
 	public String getIsSzCloud() {
@@ -1101,4 +1106,36 @@ public class WorkInvoice extends ActEntity<WorkInvoice> {
 	public void setOmsAttachmentUrl(String omsAttachmentUrl) {
 		this.omsAttachmentUrl = omsAttachmentUrl;
 	}
+
+	public String getRedInvoiceJson() {
+		return redInvoiceJson;
+	}
+
+	public void setRedInvoiceJson(String redInvoiceJson) {
+		this.redInvoiceJson = redInvoiceJson;
+	}
+
+	public String getBlueDownloadInvoiceJson() {
+		return blueDownloadInvoiceJson;
+	}
+
+	public void setBlueDownloadInvoiceJson(String blueDownloadInvoiceJson) {
+		this.blueDownloadInvoiceJson = blueDownloadInvoiceJson;
+	}
+
+	public String getRetryInvoiceJson() {
+		return retryInvoiceJson;
+	}
+
+	public void setRetryInvoiceJson(String retryInvoiceJson) {
+		this.retryInvoiceJson = retryInvoiceJson;
+	}
+
+	public String getRedDownloadInvoiceJson() {
+		return redDownloadInvoiceJson;
+	}
+
+	public void setRedDownloadInvoiceJson(String redDownloadInvoiceJson) {
+		this.redDownloadInvoiceJson = redDownloadInvoiceJson;
+	}
 }

+ 2 - 1
src/main/java/com/jeeplus/modules/workinvoice/service/OMS/InvoiceDownloadService.java

@@ -36,6 +36,7 @@ public class InvoiceDownloadService {
     private static final String appId = Global.getConfig("omsAppId");
     private static final String appKey = Global.getConfig("omsAppKey");
     private static final String deptCode = Global.getConfig("omsDeptCode");
+    private static final String omsUrl = Global.getConfig("omsUrl");
 
 
     @Autowired
@@ -137,7 +138,7 @@ public class InvoiceDownloadService {
             String jsonInvoiceDownStr = JSON.toJSONString(invoiceDownInfo);
 
             String invoiceResultStr = HttpPostJsonUtil.doPost(
-                    "https://www.oms.ejinshui-cloud.com:8899/prod-api/output/server/invoice/download",
+                    omsUrl + "/prod-api/output/server/invoice/download",
                     jsonInvoiceDownStr
             );
             System.out.println("[InvoiceDownloadTask] 发票解析结果:" + invoiceResultStr);

+ 130 - 6
src/main/java/com/jeeplus/modules/workinvoice/service/OMS/OMSDisposeService.java

@@ -1,6 +1,8 @@
 package com.jeeplus.modules.workinvoice.service.OMS;
 
 import com.alibaba.fastjson.JSON;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
 import com.jeeplus.common.config.Global;
 import com.jeeplus.common.utils.JedisUtils;
 import com.jeeplus.common.utils.StringUtils;
@@ -21,6 +23,7 @@ import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import redis.clients.jedis.Jedis;
 
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.UUID;
@@ -37,6 +40,7 @@ public class OMSDisposeService {
     private static final String appId = Global.getConfig("omsAppId");
     private static final String appKey = Global.getConfig("omsAppKey");
     private static final String deptCode = Global.getConfig("omsDeptCode");
+    private static final String omsUrl = Global.getConfig("omsUrl");
     //如果接口访问不正确,可以循环访问的次数
     private final int remainRetryTimes = 20;
 
@@ -51,6 +55,10 @@ public class OMSDisposeService {
     @Autowired
     private WorkInvoiceService workInvoiceService;
 
+    // 注入SpringBoot内置的JSON序列化工具(无额外依赖)
+    @Autowired
+    private ObjectMapper objectMapper;
+
     /**
      * 用于生成开蓝票信息
      * @param map
@@ -130,7 +138,7 @@ public class OMSDisposeService {
                     InvoiceTokenInfo.setData(string);
                     String jsonInvoiceStr = JSON.toJSONString(InvoiceTokenInfo);
 
-                    String jsonInvoicResultStr = HttpPostJsonUtil.doPost("https://www.oms.ejinshui-cloud.com:8899/prod-api/output/server/order/upload", jsonInvoiceStr);
+                    String jsonInvoicResultStr = HttpPostJsonUtil.doPost(omsUrl + "/prod-api/output/server/order/upload", jsonInvoiceStr);
                     System.out.println("✅ 订单提交接口返回值:" + jsonInvoicResultStr);
                     map.put("订单接口信息", jsonInvoicResultStr);
 
@@ -184,17 +192,53 @@ public class OMSDisposeService {
             tokenInfo.setAppKey(appKey);
             tokenInfo.setExchangeId(UUID.randomUUID().toString());
             String jsonStr = JSON.toJSONString(tokenInfo);
-            String accessTokenStr = HttpPostJsonUtil.doPost("https://www.oms.ejinshui-cloud.com:8899/prod-api/server/accessToken", jsonStr);
+            String accessTokenStr = HttpPostJsonUtil.doPost(omsUrl + "/prod-api/server/accessToken", jsonStr);
 
             if(StringUtils.isBlank(accessTokenStr)){
                 System.err.println("获取AccessToken失败:接口返回空,剩余重试次数:"+remainRetryTimes);
-                return "";
+                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失败:接口返回空,重试次数耗尽!");
+                    //需要将错误信息保存到对应开票信息表中
+                    WorkInvoice workInvoice = workInvoiceDao.get(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);
-                return "";
+                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失败:返回结果解析异常,重试次数耗尽!");
+                    //需要将错误信息保存到对应开票信息表中
+                    WorkInvoice workInvoice = workInvoiceDao.get(workInvoiceId);
+                    if(null != workInvoice){
+                        workInvoice.setOmsAccessTokenError("获取AccessToken失败:返回结果解析异常");
+                        //修改结果
+                        workInvoiceDao.updateAccessTokenErrorById(workInvoice);
+                    }
+                    //如果需要 可以将执行失败信息通过短信通知业务发起人
+                    handleInvoiceRetryAllFail("", workInvoiceId, "获取AccessToken失败:返回结果解析异常", informType); // 解析失败也执行兜底方法
+
+                    return "";
+                }
             }
 
             String code = resultTokenInfo.getResult().getCode();
@@ -331,6 +375,7 @@ public class OMSDisposeService {
      * @param getKey         获取token的key
      * @param initiationType 开票类型(蓝票/红票)
      */
+    @Transactional(readOnly = false)
     public void saveInvoiceRetryScheduledTaskToRedis(String jsonInvoiceStr ,String accessToken, String workInvoiceId, String getKey, String initiationType) {
         Jedis jedis = null;
         // 硬编码:初始重试次数100次
@@ -359,6 +404,36 @@ public class OMSDisposeService {
 
             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和实体,风格统一)
+            WorkInvoice workInvoice = new WorkInvoice();
+            workInvoice.setId(workInvoiceId);
+            workInvoice.setRetryInvoiceJson(retryTaskJson);
+            // 处理DAO更新结果,按你的风格打印控制台信息
+            workInvoiceDao.updateRedInvoiceJsonByWorkInvoiceId(workInvoice);
+
         } catch (Exception e) {
             e.printStackTrace();
             System.err.println("❌ 存入9998重试任务到Redis失败,订单号:" + workInvoiceId + ",原因:" + e.getMessage());
@@ -373,6 +448,7 @@ public class OMSDisposeService {
      * @param accessToken
      * @param workInvoiceId 开票的id
      */
+    @Transactional(readOnly = false)
     public void saveInvoiceDownloadTaskToRedis(String accessToken, String workInvoiceId, String informType) {
         Jedis jedis = null;
         try {
@@ -383,6 +459,28 @@ public class OMSDisposeService {
             jedis.hset(redisKey, "informType", informType);
             jedis.hset(redisKey, "firstExecTime", String.valueOf(System.currentTimeMillis()));
             jedis.expire(redisKey, seconds); // 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", seconds);
+            downloadTaskMap.put("redisStoreTime", redisStoreTime); // 新增秒级存储时间
+
+            // Map转JSON字符串(单独捕获序列化异常,不影响核心逻辑)
+            String downloadTaskJson = objectMapper.writeValueAsString(downloadTaskMap);
+
+            // 更新发票表(和红冲方法用相同的DAO/实体,保持风格统一)
+            WorkInvoice workInvoice = new WorkInvoice();
+            workInvoice.setId(workInvoiceId);
+            workInvoice.setBlueDownloadInvoiceJson(downloadTaskJson);
+            workInvoiceDao.updateRedInvoiceJsonByWorkInvoiceId(workInvoice);
+
         } catch (Exception e) {
             e.printStackTrace();
         } finally {
@@ -463,7 +561,7 @@ public class OMSDisposeService {
             InvoiceTokenInfo.setData(string);
             String jsonInvoiceStr = JSON.toJSONString(InvoiceTokenInfo);
 
-            String jsonInvoicResultStr = HttpPostJsonUtil.doPost("https://www.oms.ejinshui-cloud.com:8899/prod-api/output/server/invoice/makeredinv", jsonInvoiceStr);
+            String jsonInvoicResultStr = HttpPostJsonUtil.doPost(omsUrl + "/prod-api/output/server/invoice/makeredinv", jsonInvoiceStr);
             System.out.println("✅ 快速红冲订单提交接口返回值:" + jsonInvoicResultStr);
             map.put("快速红冲订单接口信息", jsonInvoicResultStr);
 
@@ -582,7 +680,7 @@ public class OMSDisposeService {
                     InvoiceTokenInfo.setData(string);
                     String jsonInvoiceStr = JSON.toJSONString(InvoiceTokenInfo);
 
-                    String jsonInvoicResultStr = HttpPostJsonUtil.doPost("https://www.oms.ejinshui-cloud.com:8899/prod-api/output/server/redApply/apply", jsonInvoiceStr);
+                    String jsonInvoicResultStr = HttpPostJsonUtil.doPost(omsUrl + "/prod-api/output/server/redApply/apply", jsonInvoiceStr);
                     System.out.println("✅ 全场景红冲订单提交接口返回值:" + jsonInvoicResultStr);
                     map.put("全场景红冲订单接口信息", jsonInvoicResultStr);
 
@@ -663,6 +761,7 @@ public class OMSDisposeService {
      * @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) {
         Jedis jedis = null;
         try {
@@ -676,6 +775,31 @@ public class OMSDisposeService {
             jedis.hset(redisKey, "informType", informType);
             jedis.hset(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);
+
+            WorkInvoice workInvoice = new WorkInvoice();
+            workInvoice.setId(workInvoiceId);
+            workInvoice.setRedInvoiceJson(redInvoiceJson);
+            // 3. 更新现有发票表的JSON字段(根据发票ID精准更新)
+            workInvoiceDao.updateRedInvoiceJsonByWorkInvoiceId(workInvoice);
+
         } catch (Exception e) {
             e.printStackTrace();
             handleInvoiceRetryAllFail(accessToken, workInvoiceId, "全类型红冲--红字确认单查询接口发起失败,请重新发起", informType); // 解析失败也执行兜底方法

+ 2 - 1
src/main/java/com/jeeplus/modules/workinvoice/service/OMS/RedInvoiceDownloadService.java

@@ -37,6 +37,7 @@ public class RedInvoiceDownloadService {
     private static final String appId = Global.getConfig("omsAppId");
     private static final String appKey = Global.getConfig("omsAppKey");
     private static final String deptCode = Global.getConfig("omsDeptCode");
+    private static final String omsUrl = Global.getConfig("omsUrl");
 
 
     @Autowired
@@ -142,7 +143,7 @@ public class RedInvoiceDownloadService {
             String jsonInvoiceDownStr = JSON.toJSONString(invoiceDownInfo);
 
             String invoiceResultStr = HttpPostJsonUtil.doPost(
-                    "https://www.oms.ejinshui-cloud.com:8899/prod-api/output/server/invoice/download",
+                    omsUrl + "/prod-api/output/server/invoice/download",
                     jsonInvoiceDownStr
             );
             System.out.println("[InvoiceDownloadTask] 发票解析结果:" + invoiceResultStr);

+ 4 - 1
src/main/java/com/jeeplus/modules/workinvoice/service/OMS/RedInvoiceRetryScheduledService.java

@@ -1,6 +1,7 @@
 package com.jeeplus.modules.workinvoice.service.OMS;
 
 import com.alibaba.fastjson.JSON;
+import com.jeeplus.common.config.Global;
 import com.jeeplus.common.utils.JedisUtils;
 import com.jeeplus.modules.workinvoice.dao.WorkInvoiceDao;
 import com.jeeplus.modules.workinvoice.entity.OMS.OMSAccessTokenInfo;
@@ -30,6 +31,8 @@ import java.util.Set;
 @Lazy(false) // 非懒加载,项目启动即初始化
 public class RedInvoiceRetryScheduledService {
 
+    private static final String omsUrl = Global.getConfig("omsUrl");
+
     // 原业务类中的核心方法需要能被定时任务调用,建议将executeOrderUploadRetry、handleInvoiceRetryAllFail等方法改为public,
     // 或通过@Autowired注入业务类实例(假设你的业务类叫InvoiceOMSService)
     @Autowired
@@ -113,7 +116,7 @@ public class RedInvoiceRetryScheduledService {
                     if(null != workInvoice){
                         // 7. 调用OMS订单上传接口重试
                         String newResultStr = HttpPostJsonUtil.doPost(
-                                "https://www.oms.ejinshui-cloud.com:8899/prod-api/output/server/order/upload",
+                                omsUrl + "/prod-api/output/server/order/upload",
                                 jsonInvoiceStr
                         );
                         System.out.println("✅ 订单" + orderNo + "9998重试调用接口返回:" + newResultStr);

+ 65 - 6
src/main/java/com/jeeplus/modules/workinvoice/service/OMS/RedInvoiceScheduledService.java

@@ -2,6 +2,7 @@ package com.jeeplus.modules.workinvoice.service.OMS;
 
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
+import com.fasterxml.jackson.databind.ObjectMapper;
 import com.jeeplus.common.config.Global;
 import com.jeeplus.common.utils.JedisUtils;
 import com.jeeplus.modules.workinvoice.dao.WorkInvoiceDao;
@@ -17,9 +18,7 @@ import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import redis.clients.jedis.Jedis;
 
-import java.util.Calendar;
-import java.util.Set;
-import java.util.UUID;
+import java.util.*;
 
 /**
  * 红字确认单查询接口回调
@@ -33,6 +32,11 @@ public class RedInvoiceScheduledService {
     private static final String appId = Global.getConfig("omsAppId");
     private static final String appKey = Global.getConfig("omsAppKey");
     private static final String deptCode = Global.getConfig("omsDeptCode");
+    private static final String omsUrl = Global.getConfig("omsUrl");
+
+    // 注入SpringBoot内置的JSON序列化工具(无额外依赖)
+    @Autowired
+    private ObjectMapper objectMapper;
 
     @Autowired
     private OMSDisposeService omsDisposeService;
@@ -187,7 +191,7 @@ public class RedInvoiceScheduledService {
             String jsonInvoiceDownStr = JSON.toJSONString(invoiceDownInfo);
 
             // 调用查询接口(红字确认单接口,即红冲的第3步)
-            String invoiceResultStr = HttpPostJsonUtil.doPost("https://www.oms.ejinshui-cloud.com:8899/prod-api/output/server/redApply/query", jsonInvoiceDownStr);
+            String invoiceResultStr = HttpPostJsonUtil.doPost(omsUrl + "/prod-api/output/server/redApply/query", jsonInvoiceDownStr);
             if (StringUtils.isBlank(invoiceResultStr)) {
                 throw new RuntimeException("查询接口返回空");
             }
@@ -294,7 +298,8 @@ public class RedInvoiceScheduledService {
     /**
      * 存入Redis(定时任务内部使用)
      */
-    private void saveRedInvoiceTaskToRedis(int remainRetryTimes, String jsonInvoicResultStr, String accessToken, String applyNo, long startTime, String informType) {
+    @Transactional(readOnly = false)
+    public void saveRedInvoiceTaskToRedis(int remainRetryTimes, String jsonInvoicResultStr, String accessToken, String applyNo, long startTime, String informType) {
         Jedis jedis = null;
         try {
             jedis = JedisUtils.getResource();
@@ -306,6 +311,35 @@ public class RedInvoiceScheduledService {
             jedis.hset(redisKey, "informType", informType);
             jedis.hset(redisKey, "startTime", String.valueOf(startTime));
             jedis.expire(redisKey, 259200 + 3600);
+
+            // ========== 追加:Redis数据转JSON,持久化到发票表(兜底逻辑) ==========
+            long redisStoreTime = System.currentTimeMillis() / 1000; // 秒级存储时间,用于后期回滚
+            // 提取Redis中startTime的字符串值,Map和Redis共用,保证数据完全一致
+            String startTimeStr = String.valueOf(startTime);
+            // 封装Map:包含Redis所有字段 + redisKey/过期时间/存储时间(保留redisKey)
+            Map<String, Object> redInvoiceMap = new HashMap<>();
+            // Redis哈希中所有原字段(与Redis完全一致)
+            redInvoiceMap.put("remainRetryTimes", remainRetryTimes);
+            redInvoiceMap.put("jsonInvoicResultStr", jsonInvoicResultStr);
+            redInvoiceMap.put("accessToken", accessToken);
+            redInvoiceMap.put("applyNo", applyNo);
+            redInvoiceMap.put("informType", informType);
+            redInvoiceMap.put("startTime", startTimeStr);
+            // 额外兜底字段(保留redisKey,贴合你的要求)
+            redInvoiceMap.put("redisKey", redisKey);
+            redInvoiceMap.put("redisExpireSeconds", 259200 + 3600);
+            redInvoiceMap.put("redisStoreTime", redisStoreTime);
+
+            // Map转JSON字符串(单独捕获序列化异常,不影响Redis核心逻辑)
+            String redInvoiceJson = objectMapper.writeValueAsString(redInvoiceMap);
+
+            // 更新发票表(唯一标识为applyNo,与Redis一致)
+            WorkInvoice workInvoice = new WorkInvoice();
+            workInvoice.setId(applyNo); // 关键:用applyNo作为更新ID,与你的唯一标识一致
+            workInvoice.setRedInvoiceJson(redInvoiceJson);
+            // 处理DAO更新,单独捕获异常,不影响核心逻辑
+            workInvoiceDao.updateRedInvoiceJsonByWorkInvoiceId(workInvoice);
+
         } catch (Exception e) {
             e.printStackTrace();
         } finally {
@@ -334,7 +368,8 @@ public class RedInvoiceScheduledService {
      * @param accessToken
      * @param workInvoiceId 开票id
      */
-    private void saveInvoiceDownloadTaskToRedis(String accessToken, String redInvOrderNo, String workInvoiceId,  String informType) {
+    @Transactional(readOnly = false)
+    public void saveInvoiceDownloadTaskToRedis(String accessToken, String redInvOrderNo, String workInvoiceId,  String informType) {
         Jedis jedis = null;
         try {
             jedis = JedisUtils.getResource();
@@ -345,6 +380,30 @@ public class RedInvoiceScheduledService {
             jedis.hset(redisKey, "informType", informType);
             jedis.hset(redisKey, "firstExecTime", String.valueOf(System.currentTimeMillis()));
             jedis.expire(redisKey, 86400); // 1天过期
+
+            // ========== 追加:Redis数据转JSON → 持久化到发票表(兜底逻辑) ==========
+            long redisStoreTime = System.currentTimeMillis() / 1000; // 秒级存储时间,用于后期回滚
+            // 封装Map:Redis所有原字段 + redisKey/过期时间/存储时间(保留redisKey)
+            Map<String, Object> downloadTaskMap = new HashMap<>(8);
+            // Redis哈希中5个原字段(与Redis键名/值完全一致,含新增的redInvOrderNo)
+            downloadTaskMap.put("accessToken", accessToken);
+            downloadTaskMap.put("redInvOrderNo", redInvOrderNo);
+            downloadTaskMap.put("workInvoiceId", workInvoiceId);
+            downloadTaskMap.put("informType", informType);
+            downloadTaskMap.put("firstExecTime", String.valueOf(System.currentTimeMillis()));
+            // 额外兜底字段(保留redisKey,后期回滚直接取用)
+            downloadTaskMap.put("redisKey", redisKey);
+            downloadTaskMap.put("redisExpireSeconds", 86400);
+            downloadTaskMap.put("redisStoreTime", redisStoreTime);
+
+            // Map转JSON字符串(单独捕获序列化异常,不影响Redis核心逻辑)
+            String downloadTaskJson = objectMapper.writeValueAsString(downloadTaskMap);
+
+            // 更新发票表(以workInvoiceId为唯一标识,与Redis一致)
+            WorkInvoice workInvoice = new WorkInvoice();
+            workInvoice.setId(workInvoiceId); // 关键:与redisKey的拼接标识一致
+            workInvoice.setRedDownloadInvoiceJson(downloadTaskJson);
+            workInvoiceDao.updateRedInvoiceJsonByWorkInvoiceId(workInvoice);
         } catch (Exception e) {
             e.printStackTrace();
         } finally {

+ 90 - 70
src/main/java/com/jeeplus/modules/workinvoice/service/WorkInvoiceService.java

@@ -5,6 +5,7 @@ package com.jeeplus.modules.workinvoice.service;
 
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
+import com.jeeplus.common.config.Global;
 import com.jeeplus.common.json.AjaxJson;
 import com.jeeplus.common.persistence.Page;
 import com.jeeplus.common.service.CrudService;
@@ -143,6 +144,9 @@ public class WorkInvoiceService extends CrudService<WorkInvoiceDao, WorkInvoice>
 
 	Pattern mobilePattern = Pattern.compile("^1[3-9]\\d{9}$");
 
+	//用于判定是否是生产环境,是否开启oms开具发票功能
+	private static final String omsEnabled = Global.getConfig("omsEnabled");
+
 	private static byte[] SYN_BYTE = new byte[0];
     @Autowired
     private UserService userService;
@@ -1853,21 +1857,26 @@ public class WorkInvoiceService extends CrudService<WorkInvoiceDao, WorkInvoice>
 							notifyRole = "审批通过";
 							workActivityProcess.setIsApproval("1");
 
-							//需要判定,此处 如果开票金额为正数,则表示是开蓝票,如果是负数,则表示是开红票
-							if(workInvoice.getMoney()>0){
-								//财务审核通过时,需要调用OMS开票接口,用于开票操作。开票完成后,再进行发送成功通知 或者失败通知
-								new ApprovalThread(workInvoice, "21").start();
-							}else{
-								//先获取对应红冲发票的数电票  票号
-								//查询关联红冲发票的开票号
-								if(1 == workInvoice.getRedInvoiceFlag() && StringUtils.isNotBlank(workInvoice.getRedInvoiceRelevancyId())){
-									String invoiceNumberStr = this.getInvoiceNumberStr(workInvoice.getRedInvoiceRelevancyId());
-									workInvoice.setInvoiceNumberStr(invoiceNumberStr);
+							//用于判定是否是生产环境,是否开启oms开具发票功能
+							boolean OMS_ENABLED = StringUtils.isNotBlank(omsEnabled) && Boolean.parseBoolean(omsEnabled);
+							if(OMS_ENABLED){
+								//需要判定,此处 如果开票金额为正数,则表示是开蓝票,如果是负数,则表示是开红票
+								if(workInvoice.getMoney()>0){
+									//财务审核通过时,需要调用OMS开票接口,用于开票操作。开票完成后,再进行发送成功通知 或者失败通知
+									new ApprovalThread(workInvoice, "21").start();
+								}else{
+									//先获取对应红冲发票的数电票  票号
+									//查询关联红冲发票的开票号
+									if(1 == workInvoice.getRedInvoiceFlag() && StringUtils.isNotBlank(workInvoice.getRedInvoiceRelevancyId())){
+										String invoiceNumberStr = this.getInvoiceNumberStr(workInvoice.getRedInvoiceRelevancyId());
+										workInvoice.setInvoiceNumberStr(invoiceNumberStr);
+									}
+									//还需要获取被红冲发票的对应invoice信息
+									new RedApprovalThread(workInvoice,workInvoice.getInvoiceNumberStr(), "21").start();
 								}
-								//还需要获取被红冲发票的对应invoice信息
-								new RedApprovalThread(workInvoice,workInvoice.getInvoiceNumberStr(), "21").start();
 							}
 
+
 							/*enname = "fpgly";
 							vars.put("fpglyList", auditUsers);
 							vars.put("fpglycount",auditUsers.size());*/
@@ -1922,20 +1931,19 @@ public class WorkInvoiceService extends CrudService<WorkInvoiceDao, WorkInvoice>
 			List<User> userList = new ArrayList<>();
 			//ProjectRecords projectRecords = projectRecordsService.getRuralMasters(workInvoice.getProject().getId());
 		if (!state) {
-			//将数据流程接点重新归属到审批状态不变,等发票开启之后 进行变更为审核通过,若失败,则变更为暂存状态并发送通知
-			users.add(workInvoice.getCreateBy());
-			//新设定的值,该值表示开票进行中
-			workInvoice.setInvoiceState("12");
-			WorkProjectNotify notify = new WorkProjectNotify();
-			notify.setNotifyId(workInvoice.getId());
-			userList = workProjectNotifyService.readByNotifyId(notify);
-
 
-
-
-
-
-				/*users.add(workInvoice.getCreateBy());
+			//用于判定是否是生产环境,是否开启oms开具发票功能
+			boolean OMS_ENABLED = StringUtils.isNotBlank(omsEnabled) && Boolean.parseBoolean(omsEnabled);
+			if(OMS_ENABLED){
+				//将数据流程接点重新归属到审批状态不变,等发票开启之后 进行变更为审核通过,若失败,则变更为暂存状态并发送通知
+				users.add(workInvoice.getCreateBy());
+				//新设定的值,该值表示开票进行中
+				workInvoice.setInvoiceState("12");
+				WorkProjectNotify notify = new WorkProjectNotify();
+				notify.setNotifyId(workInvoice.getId());
+				userList = workProjectNotifyService.readByNotifyId(notify);
+			}else{
+				users.add(workInvoice.getCreateBy());
 				if ("yes".equals(workInvoice.getAct().getFlag())) {
 					title = "项目【"+ projectNameStr +"】发票申请通过";
 					str = "发票金额:" + workInvoice.getMoney() + "(元)。项目【"+ projectNameStr +"】发票申请通过,发票申请编号:"+workInvoice.getNumber();
@@ -1978,8 +1986,7 @@ public class WorkInvoiceService extends CrudService<WorkInvoiceDao, WorkInvoice>
 					}
 				}
 				workActivityProcessService.deleteProcessIdAuditUsers(workInvoice.getProcessInstanceId());
-				*/
-
+			}
 			} else {
 				if (StringUtils.isNotBlank(workActivityMenu.getProcessType()) && !workActivityMenu.getProcessType().equals("newWorkInvoiceBranch")) {
 					WorkProjectNotify notify = new WorkProjectNotify();
@@ -2637,22 +2644,28 @@ public class WorkInvoiceService extends CrudService<WorkInvoiceDao, WorkInvoice>
 						notifyRole = "审批通过";
 						workActivityProcess.setIsApproval("1");
 
-						//需要判定,此处 如果开票金额为正数,则表示是开蓝票,如果是负数,则表示是开红票
-						if(workInvoice.getMoney()>0){
-							//财务审核通过时,需要调用OMS开票接口,用于开票操作。开票完成后,再进行发送成功通知 或者失败通知
-							new ApprovalThread(workInvoice,"213").start();
-						}else{
-							//先获取对应红冲发票的数电票  票号
-							//查询关联红冲发票的开票号
-							if(1 == workInvoice.getRedInvoiceFlag() && StringUtils.isNotBlank(workInvoice.getRedInvoiceRelevancyId())){
-								String invoiceNumberStr = this.getInvoiceNumberStr(workInvoice.getRedInvoiceRelevancyId());
-								workInvoice.setInvoiceNumberStr(invoiceNumberStr);
+						//用于判定是否是生产环境,是否开启oms开具发票功能
+						boolean OMS_ENABLED = StringUtils.isNotBlank(omsEnabled) && Boolean.parseBoolean(omsEnabled);
+						if(OMS_ENABLED){
+							//需要判定,此处 如果开票金额为正数,则表示是开蓝票,如果是负数,则表示是开红票
+							if(workInvoice.getMoney()>0){
+								//财务审核通过时,需要调用OMS开票接口,用于开票操作。开票完成后,再进行发送成功通知 或者失败通知
+								new ApprovalThread(workInvoice,"213").start();
+							}else{
+								//先获取对应红冲发票的数电票  票号
+								//查询关联红冲发票的开票号
+								if(1 == workInvoice.getRedInvoiceFlag() && StringUtils.isNotBlank(workInvoice.getRedInvoiceRelevancyId())){
+									String invoiceNumberStr = this.getInvoiceNumberStr(workInvoice.getRedInvoiceRelevancyId());
+									workInvoice.setInvoiceNumberStr(invoiceNumberStr);
+								}
+								//还需要获取被红冲发票的对应invoice信息
+								new RedApprovalThread(workInvoice,workInvoice.getInvoiceNumberStr(),"213").start();
 							}
-							//还需要获取被红冲发票的对应invoice信息
-							new RedApprovalThread(workInvoice,workInvoice.getInvoiceNumberStr(),"213").start();
 						}
 
 
+
+
 							/*enname = "fpgly";
 							vars.put("fpglyList", auditUsers);
 							vars.put("fpglycount",auditUsers.size());*/
@@ -2701,40 +2714,26 @@ public class WorkInvoiceService extends CrudService<WorkInvoiceDao, WorkInvoice>
 		List<User> userList = new ArrayList<>();
 		//ProjectRecords projectRecords = projectRecordsService.getRuralMasters(workInvoice.getProject().getId());
 		if (!state) {
-			//将数据流程接点重新归属到审批状态不变,等发票开启之后 进行变更为审核通过,若失败,则变更为暂存状态并发送通知
-			users.add(workInvoice.getCreateBy());
-			//新设定的值,该值表示开票进行中
-			workInvoice.setInvoiceState("12");
-			WorkProjectNotify notify = new WorkProjectNotify();
-			notify.setNotifyId(workInvoice.getId());
-			userList = workProjectNotifyService.readByNotifyId(notify);
-
-
-			/*if ("yes".equals(workInvoice.getAct().getFlag())) {
-				title = "项目【"+ projectNameStr +"】发票申请通过";
-				str = "项目【"+ projectNameStr +"】发票申请通过,发票申请编号:"+workInvoice.getNumber();
-				workInvoice.setInvoiceState("5");
-				WorkProjectNotify notify = new WorkProjectNotify();
-				notify.setNotifyId(workInvoice.getId());
-				userList = workProjectNotifyService.readByNotifyId(notify);
-				workProjectNotifyService
-						.save(UtilNotify
-								.saveNotify(workInvoice.getId(),
-										workInvoice.getCreateBy(),
-										workInvoice.getCompanyId(),
-										title,
-										str,
-										"213",
-										"0",
-										"待通知",
-										notifyRole));
 
-			} else {
+			//用于判定是否是生产环境,是否开启oms开具发票功能
+			boolean OMS_ENABLED = StringUtils.isNotBlank(omsEnabled) && Boolean.parseBoolean(omsEnabled);
+			if(OMS_ENABLED){
+				//将数据流程接点重新归属到审批状态不变,等发票开启之后 进行变更为审核通过,若失败,则变更为暂存状态并发送通知
+				users.add(workInvoice.getCreateBy());
+				//新设定的值,该值表示开票进行中
+				workInvoice.setInvoiceState("12");
 				WorkProjectNotify notify = new WorkProjectNotify();
 				notify.setNotifyId(workInvoice.getId());
 				userList = workProjectNotifyService.readByNotifyId(notify);
-				if (StringUtils.isNotBlank(workInvoice.getInvoiceState()) && !workInvoice.getInvoiceState().equals("3")){
-					workInvoice.setInvoiceState("4");
+			}else{
+				users.add(workInvoice.getCreateBy());
+				if ("yes".equals(workInvoice.getAct().getFlag())) {
+					title = "项目【"+ projectNameStr +"】发票申请通过";
+					str = "项目【"+ projectNameStr +"】发票申请通过,发票申请编号:"+workInvoice.getNumber();
+					workInvoice.setInvoiceState("5");
+					WorkProjectNotify notify = new WorkProjectNotify();
+					notify.setNotifyId(workInvoice.getId());
+					userList = workProjectNotifyService.readByNotifyId(notify);
 					workProjectNotifyService
 							.save(UtilNotify
 									.saveNotify(workInvoice.getId(),
@@ -2746,9 +2745,28 @@ public class WorkInvoiceService extends CrudService<WorkInvoiceDao, WorkInvoice>
 											"0",
 											"待通知",
 											notifyRole));
+
+				} else {
+					WorkProjectNotify notify = new WorkProjectNotify();
+					notify.setNotifyId(workInvoice.getId());
+					userList = workProjectNotifyService.readByNotifyId(notify);
+					if (StringUtils.isNotBlank(workInvoice.getInvoiceState()) && !workInvoice.getInvoiceState().equals("3")){
+						workInvoice.setInvoiceState("4");
+						workProjectNotifyService
+								.save(UtilNotify
+										.saveNotify(workInvoice.getId(),
+												workInvoice.getCreateBy(),
+												workInvoice.getCompanyId(),
+												title,
+												str,
+												"213",
+												"0",
+												"待通知",
+												notifyRole));
+					}
 				}
+				workActivityProcessService.deleteProcessIdAuditUsers(workInvoice.getProcessInstanceId());
 			}
-			workActivityProcessService.deleteProcessIdAuditUsers(workInvoice.getProcessInstanceId());*/
 		} else {
 			if (StringUtils.isNotBlank(workActivityMenu.getProcessType()) && !workActivityMenu.getProcessType().equals("newWorkInvoiceNotProject")) {
 				WorkProjectNotify notify = new WorkProjectNotify();
@@ -4296,6 +4314,7 @@ public class WorkInvoiceService extends CrudService<WorkInvoiceDao, WorkInvoice>
 		AjaxJson j = new AjaxJson();
 		//查询开票人员的手机号
 		User user = userDao.get(workInvoice.getCreateBy().getId());
+		user.setMobile("18164266544");
 		if (StringUtils.isNotBlank(user.getMobile()) && mobilePattern.matcher(user.getMobile().trim()).matches() ) {
 			//验证手机号是否已经注册
 			if(userDao.validateMobile("mobile") == null){
@@ -4472,6 +4491,7 @@ public class WorkInvoiceService extends CrudService<WorkInvoiceDao, WorkInvoice>
 		AjaxJson j = new AjaxJson();
 		//查询开票人员的手机号
 		User user = userDao.get(workInvoice.getCreateBy().getId());
+		user.setMobile("18164266544");
 		if (StringUtils.isNotBlank(user.getMobile()) && mobilePattern.matcher(user.getMobile().trim()).matches() ) {
 			//验证手机号是否已经注册
 			if(userDao.validateMobile("mobile") == null){

+ 5 - 3
src/main/resources/jeeplus.properties

@@ -423,10 +423,12 @@ omsDeptCode: JSXG01
 omsSellerTaxno: 91320000746823994F
 #销售方名称
 omsSellerName: 江苏兴光项目管理有限公司
-#销售方名称
+#销售方银行名称
 omsBankName: 中信银行南京龙江支行
-#销售方名称
+#销售方银行账号
 omsBankAccount: 7329010182600006811
 #访问接口地址前缀
 #omsUrl: https://oms-sandbox.einvoice.js.cn:7079
-omsUrl: https://www.oms.ejinshui-cloud.com:8899
+omsUrl: https://www.oms.ejinshui-cloud.com:8899
+#用于判定是否开启oms开票流程事件
+omsEnabled: false

+ 20 - 0
src/main/resources/mappings/modules/workinvoice/WorkInvoiceDao.xml

@@ -3388,6 +3388,26 @@
 		select * from work_invoice_tax_classification_code where del_flag = 0 and billing_content_id = #{billingContent}
 	</select>
 
+	<update id="updateRedInvoiceJsonByWorkInvoiceId">
+		UPDATE work_invoice
+		<!-- 用MyBatis的<set>标签替换原生SET,自动处理首字段逗号问题 -->
+		<set>
+			<if test="null != blueDownloadInvoiceJson and '' != blueDownloadInvoiceJson">
+				blue_download_invoice_json = #{blueDownloadInvoiceJson}
+			</if>
+			<if test="null != retryInvoiceJson and '' != retryInvoiceJson">
+				retry_invoice_json = #{retryInvoiceJson}
+			</if>
+			<if test="null != redInvoiceJson and '' != redInvoiceJson">
+				red_invoice_json = #{redInvoiceJson}
+			</if>
+			<if test="null != redDownloadInvoiceJson and '' != redDownloadInvoiceJson">
+				red_download_invoice_json = #{redDownloadInvoiceJson}
+			</if>
+		</set>
+		WHERE id = #{id}
+	</update>
+
 
 
 </mapper>

+ 1 - 1
src/main/webapp/webpage/modules/workinvoice/workInvoiceAuditEnd.jsp

@@ -803,7 +803,7 @@
 			<div class="layui-item layui-col-sm12 with-textarea">
 				<label class="layui-form-label double-line">备注:</label>
 				<div class="layui-input-block">
-					<form:textarea path="remarks" readonly="true" htmlEscape="false" rows="4" class="form-control" style="background-color: #f1f1f1" />
+					<form:textarea path="remarks" htmlEscape="false" rows="4" class="form-control" />
 				</div>
 			</div>