|
|
@@ -1,278 +0,0 @@
|
|
|
-package com.jeeplus.modules.workinvoice.utils;
|
|
|
-import com.alibaba.fastjson.JSON;
|
|
|
-import com.alibaba.fastjson.JSONObject;
|
|
|
-import com.jeeplus.common.config.Global;
|
|
|
-import com.jeeplus.modules.workinvoice.entity.OMS.OMSAccessTokenInfo;
|
|
|
-import com.jeeplus.modules.workinvoice.entity.OMS.fastRed.OMSRedInvoiceConfirmResponse;
|
|
|
-import org.springframework.scheduling.annotation.Scheduled;
|
|
|
-import org.springframework.stereotype.Component;
|
|
|
-import org.apache.commons.lang3.StringUtils;
|
|
|
-import redis.clients.jedis.Jedis;
|
|
|
-
|
|
|
-import java.util.Calendar;
|
|
|
-import java.util.Set;
|
|
|
-import java.util.UUID;
|
|
|
-
|
|
|
-/**
|
|
|
- * 红冲任务独立执行器(仅从Redis取数,全量执行业务逻辑,8:00-18:00每小时执行)
|
|
|
- */
|
|
|
-@Component
|
|
|
-public class RedInvoiceScheduledTask {
|
|
|
-
|
|
|
- private static final String appId = Global.getConfig("omsAppId");
|
|
|
- private static final String appKey = Global.getConfig("omsAppKey");
|
|
|
- private static final String deptCode = Global.getConfig("omsDeptCode");
|
|
|
-
|
|
|
-
|
|
|
- // ========== 2. 定时任务入口(8:00-18:00每小时执行) ==========
|
|
|
- @Scheduled(cron = "0 0 */1 * * ?")
|
|
|
- public void processAllRedInvoiceTasks() {
|
|
|
- // 时间窗口校验
|
|
|
- Calendar now = Calendar.getInstance();
|
|
|
- int hour = now.get(Calendar.HOUR_OF_DAY);
|
|
|
- if (hour < 8 || hour >= 18) {
|
|
|
- System.out.println("[定时任务] 非业务时段,跳过");
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- Jedis jedis = null;
|
|
|
- try {
|
|
|
- jedis = JedisUtils.getResource();
|
|
|
- Set<String> taskKeys = jedis.keys("OMS_red_invoice_task:*");
|
|
|
- if (taskKeys.isEmpty()) {
|
|
|
- System.out.println("[定时任务] 暂无待处理任务");
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- // 遍历处理所有Redis任务
|
|
|
- for (String taskKey : taskKeys) {
|
|
|
- String applyNo = taskKey.replace("OMS_red_invoice_task:", "");
|
|
|
- // 读取Redis参数
|
|
|
- String remainRetryTimesStr = jedis.hget(taskKey, "remainRetryTimes");
|
|
|
- String jsonInvoicResultStr = jedis.hget(taskKey, "jsonInvoicResultStr");
|
|
|
- String accessToken = jedis.hget(taskKey, "accessToken");
|
|
|
- String startTimeStr = jedis.hget(taskKey, "startTime");
|
|
|
-
|
|
|
- // 参数校验
|
|
|
- if (StringUtils.isAnyBlank(remainRetryTimesStr, accessToken, startTimeStr)) {
|
|
|
- jedis.del(taskKey);
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- // 转换参数并执行任务
|
|
|
- int remainRetryTimes = Integer.parseInt(remainRetryTimesStr);
|
|
|
- long startTime = Long.parseLong(startTimeStr);
|
|
|
- executeRedInvoiceTask(applyNo, remainRetryTimes, jsonInvoicResultStr, accessToken, startTime);
|
|
|
- }
|
|
|
- } catch (Exception e) {
|
|
|
- e.printStackTrace();
|
|
|
- } finally {
|
|
|
- if (jedis != null) jedis.close();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- // ========== 1. 封装所有需要的业务逻辑(独立执行,不依赖原有业务类) ==========
|
|
|
- /**
|
|
|
- * 核心:执行单个红冲任务的全流程逻辑
|
|
|
- */
|
|
|
- private void executeRedInvoiceTask(String applyNo, int remainRetryTimes, String jsonInvoicResultStr, String accessToken, long startTime) {
|
|
|
- try {
|
|
|
- // 步骤1:3天超时判断
|
|
|
- if (System.currentTimeMillis() - startTime > 259200000L) {
|
|
|
- System.err.println("❌ 任务["+applyNo+"]超时,触发兜底逻辑");
|
|
|
- handleInvoiceRetryAllFail(accessToken);
|
|
|
- deleteRedInvoiceTaskFromRedis(applyNo);
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- // 步骤2:首次执行(有jsonInvoicResultStr)→ 解析结果,触发查询
|
|
|
- if (StringUtils.isNotBlank(jsonInvoicResultStr)) {
|
|
|
- OMSAccessTokenInfo resultTokenInfo = JSON.parseObject(jsonInvoicResultStr, OMSAccessTokenInfo.class);
|
|
|
- if (null == resultTokenInfo || null == resultTokenInfo.getResult() || !"0000".equals(resultTokenInfo.getResult().getCode())) {
|
|
|
- System.err.println("❌ 任务["+applyNo+"]解析失败,触发兜底");
|
|
|
- handleInvoiceRetryAllFail(accessToken);
|
|
|
- deleteRedInvoiceTaskFromRedis(applyNo);
|
|
|
- return;
|
|
|
- }
|
|
|
- // 解析成功,调用查询接口
|
|
|
- callRedInvoiceConfirmQuery(remainRetryTimes, accessToken, applyNo, startTime);
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- // 步骤3:后续重试(无jsonInvoicResultStr)→ 直接调用查询接口
|
|
|
- callRedInvoiceConfirmQuery(remainRetryTimes, accessToken, applyNo, startTime);
|
|
|
-
|
|
|
- } catch (Exception e) {
|
|
|
- e.printStackTrace();
|
|
|
- // 异常后重试次数-1,重新存入Redis
|
|
|
- if (remainRetryTimes > 1) {
|
|
|
- saveRedInvoiceTaskToRedis(remainRetryTimes - 1, jsonInvoicResultStr, accessToken, applyNo, startTime);
|
|
|
- } else {
|
|
|
- handleInvoiceRetryAllFail(accessToken);
|
|
|
- deleteRedInvoiceTaskFromRedis(applyNo);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 调用红字确认单查询接口(核心业务逻辑)
|
|
|
- */
|
|
|
- private void callRedInvoiceConfirmQuery(int remainRetryTimes, String accessToken, String applyNo, long startTime) {
|
|
|
- try {
|
|
|
- // 组装查询参数
|
|
|
- OMSNationUtil util = new OMSNationUtil();
|
|
|
- String queryData = util.neatenAllScenarioRedInvoiceConfirmQueryData(applyNo);
|
|
|
- OMSAccessTokenInfo invoiceDownInfo = new OMSAccessTokenInfo();
|
|
|
- invoiceDownInfo.setAppId(appId);
|
|
|
- invoiceDownInfo.setAppKey(appKey);
|
|
|
- invoiceDownInfo.setExchangeId(UUID.randomUUID().toString());
|
|
|
- invoiceDownInfo.setAccessToken(accessToken);
|
|
|
- invoiceDownInfo.setData(queryData);
|
|
|
- String jsonInvoiceDownStr = JSON.toJSONString(invoiceDownInfo);
|
|
|
-
|
|
|
- // 调用查询接口
|
|
|
- String invoiceResultStr = HttpPostJsonUtil.doPost("https://oms-sandbox.einvoice.js.cn:7079/prod-api/output/server/redApply/query", jsonInvoiceDownStr);
|
|
|
- if (StringUtils.isBlank(invoiceResultStr)) {
|
|
|
- throw new RuntimeException("查询接口返回空");
|
|
|
- }
|
|
|
-
|
|
|
- // 解析查询结果
|
|
|
- OMSAccessTokenInfo resultDownInfo = JSON.parseObject(invoiceResultStr, OMSAccessTokenInfo.class);
|
|
|
- if (null == resultDownInfo.getResult() || !"0000".equals(resultDownInfo.getResult().getCode())) {
|
|
|
- throw new RuntimeException("查询接口返回错误码:" + (resultDownInfo.getResult() != null ? resultDownInfo.getResult().getCode() : "NULL"));
|
|
|
- }
|
|
|
-
|
|
|
- String invoceDownJsonStr = OMSNationUtil.extractFromBase64OnClassStr(resultDownInfo.getData().toString());
|
|
|
- OMSRedInvoiceConfirmResponse invoiceInfo = JSONObject.parseObject(invoceDownJsonStr, OMSRedInvoiceConfirmResponse.class);
|
|
|
- String confirmStatus = invoiceInfo.getConfirmStatus();
|
|
|
-
|
|
|
- // 判断状态,处理不同分支
|
|
|
- switch (confirmStatus) {
|
|
|
- case "01":
|
|
|
- case "04":
|
|
|
- if ("3".equals(invoiceInfo.getMakeStatus())) {
|
|
|
- // ========== 仅此处微调:删除直接调用,改为存入Redis ==========
|
|
|
- // 原代码 ↓
|
|
|
- // ThreadPoolUtil.executeDelay(30, () -> {
|
|
|
- // executeInvoiceDownloadWithRetry(5, accessToken, invoiceInfo.getRedInvOrderNo());
|
|
|
- // });
|
|
|
- // 新代码 ↑
|
|
|
- String redInvOrderNo = invoiceInfo.getRedInvOrderNo();
|
|
|
- // 存入Redis,由InvoiceDownloadTask接管
|
|
|
- saveInvoiceDownloadTaskToRedis(accessToken, redInvOrderNo);
|
|
|
- System.out.println("✅ 解析开票数据任务["+redInvOrderNo+"]已存入Redis,由InvoiceDownloadTask接管重试");
|
|
|
-
|
|
|
- deleteRedInvoiceTaskFromRedis(applyNo); // 成功后删除Redis
|
|
|
- } else if ("1".equals(invoiceInfo.getMakeStatus()) || "4".equals(invoiceInfo.getMakeStatus())) {
|
|
|
- // 开票中,重新存入Redis等待下次重试
|
|
|
- saveRedInvoiceTaskToRedis(remainRetryTimes, "", accessToken, applyNo, startTime);
|
|
|
- } else {
|
|
|
- handleInvoiceRetryAllFail(accessToken);
|
|
|
- deleteRedInvoiceTaskFromRedis(applyNo);
|
|
|
- }
|
|
|
- break;
|
|
|
- case "02":
|
|
|
- case "03":
|
|
|
- case "15":
|
|
|
- // 待确认,重新存入Redis等待下次重试
|
|
|
- saveRedInvoiceTaskToRedis(remainRetryTimes, "", accessToken, applyNo, startTime);
|
|
|
- break;
|
|
|
- default:
|
|
|
- // 失败状态,兜底+删除Redis
|
|
|
- handleInvoiceRetryAllFail(accessToken);
|
|
|
- deleteRedInvoiceTaskFromRedis(applyNo);
|
|
|
- break;
|
|
|
- }
|
|
|
- } catch (Exception e) {
|
|
|
- e.printStackTrace();
|
|
|
- // 接口调用失败,重试次数-1后重新存入Redis
|
|
|
- if (remainRetryTimes > 1) {
|
|
|
- saveRedInvoiceTaskToRedis(remainRetryTimes - 1, "", accessToken, applyNo, startTime);
|
|
|
- } else {
|
|
|
- handleInvoiceRetryAllFail(accessToken);
|
|
|
- deleteRedInvoiceTaskFromRedis(applyNo);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 兜底逻辑
|
|
|
- */
|
|
|
- public void handleInvoiceRetryAllFail(String accessToken) {
|
|
|
- System.err.println("📢 执行失败兜底逻辑:更新系统状态 + 通知发起人");
|
|
|
- // 此处替换为你的实际兜底逻辑(如更新数据库、发送通知等)
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 存入Redis(定时任务内部使用)
|
|
|
- */
|
|
|
- private void saveRedInvoiceTaskToRedis(int remainRetryTimes, String jsonInvoicResultStr, String accessToken, String applyNo, long startTime) {
|
|
|
- Jedis jedis = null;
|
|
|
- try {
|
|
|
- jedis = JedisUtils.getResource();
|
|
|
- String redisKey = "OMS_red_invoice_task:" + applyNo;
|
|
|
- jedis.hset(redisKey, "remainRetryTimes", String.valueOf(remainRetryTimes));
|
|
|
- jedis.hset(redisKey, "jsonInvoicResultStr", jsonInvoicResultStr);
|
|
|
- jedis.hset(redisKey, "accessToken", accessToken);
|
|
|
- jedis.hset(redisKey, "applyNo", applyNo);
|
|
|
- jedis.hset(redisKey, "startTime", String.valueOf(startTime));
|
|
|
- jedis.expire(redisKey, 259200 + 3600);
|
|
|
- } catch (Exception e) {
|
|
|
- e.printStackTrace();
|
|
|
- } finally {
|
|
|
- if (jedis != null) jedis.close();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 删除Redis任务
|
|
|
- */
|
|
|
- private void deleteRedInvoiceTaskFromRedis(String applyNo) {
|
|
|
- Jedis jedis = null;
|
|
|
- try {
|
|
|
- jedis = JedisUtils.getResource();
|
|
|
- jedis.del("OMS_red_invoice_task:" + applyNo);
|
|
|
- } catch (Exception e) {
|
|
|
- e.printStackTrace();
|
|
|
- } finally {
|
|
|
- if (jedis != null) jedis.close();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // ========== 3. 工具类依赖(替换为你的实际工具类) ==========
|
|
|
- // 此处仅为占位,需替换为你项目中实际的工具类实例/注入
|
|
|
- public static class JedisUtils {
|
|
|
- public static Jedis getResource() {
|
|
|
- // 替换为你的Redis连接获取逻辑
|
|
|
- return null;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private static class ThreadPoolUtil {
|
|
|
- public static void executeDelay(int seconds, Runnable runnable) {
|
|
|
- // 替换为你的线程池延迟执行逻辑
|
|
|
- new Thread(runnable).start();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // ========== 新增:解析开票数据Redis操作(仅新增,不修改原有) ==========
|
|
|
- private void saveInvoiceDownloadTaskToRedis(String accessToken, String orderno) {
|
|
|
- Jedis jedis = null;
|
|
|
- try {
|
|
|
- jedis = JedisUtils.getResource();
|
|
|
- String redisKey = "red_invoice_download:" + orderno;
|
|
|
- jedis.hset(redisKey, "accessToken", accessToken);
|
|
|
- jedis.hset(redisKey, "orderno", orderno);
|
|
|
- jedis.hset(redisKey, "firstExecTime", String.valueOf(System.currentTimeMillis()));
|
|
|
- jedis.expire(redisKey, 86400); // 1天过期
|
|
|
- } catch (Exception e) {
|
|
|
- e.printStackTrace();
|
|
|
- } finally {
|
|
|
- if (jedis != null) jedis.close();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- // 其他实体类(OMSNationUtil、OMSAccessTokenInfo等)替换为你项目中的实际类
|
|
|
-}
|