提交 9aa1a9c3 authored 作者: 窦馨雨's avatar 窦馨雨

合并分支 'dxy' 到 'qa'

新增定时任务每小时同步质检报告到T100 查看合并请求 !129
package com.sfa.job.domain.zzcenter.dao;
import com.sfa.job.pojo.zzcenter.ZzProductQualityDto;
import java.util.List;
/**
* @author : liqiulin
* @date : 2025-10-30 15
* @describe :
*/
public interface IZzProductQualityDao {
List<ZzProductQualityDto> selectListBySyncStatus(Integer syncStatus);
Integer updateSyncStatus(ZzProductQualityDto zzProductQualityDto);
}
package com.sfa.job.domain.zzcenter.dao.impl;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.sfa.common.core.utils.bean.BeanUtils;
import com.sfa.job.domain.zzcenter.dao.IZzProductQualityDao;
import com.sfa.job.domain.zzcenter.entity.ZzProductQuality;
import com.sfa.job.domain.zzcenter.mapper.ZzProductQualityMapper;
import com.sfa.job.pojo.zzcenter.ZzProductQualityDto;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @author : liqiulin
* @date : 2025-10-30 15
* @describe :
*/
@Service
@DS("bi")
public class ZzProductQualityDaoImpl implements IZzProductQualityDao {
@Autowired
private ZzProductQualityMapper zzProductQualityMapper;
@Override
public List<ZzProductQualityDto> selectListBySyncStatus(Integer syncStatus) {
LambdaQueryWrapper<ZzProductQuality> qw = new LambdaQueryWrapper<>();
qw.eq(ZzProductQuality::getSyncStatus, syncStatus);
List<ZzProductQuality> zzProductQualityList = zzProductQualityMapper.selectList(qw);
return BeanUtils.transitionDtos(zzProductQualityList, ZzProductQualityDto.class);
}
@Override
public Integer updateSyncStatus(ZzProductQualityDto zzProductQualityDto) {
ZzProductQuality zzProductQuality = new ZzProductQuality();
BeanUtils.copyProperties(zzProductQualityDto, zzProductQuality);
return zzProductQualityMapper.updateById(zzProductQuality);
}
}
package com.sfa.job.domain.zzcenter.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.util.Date;
import lombok.Data;
/**
* 证照中心-质检报告表
* @TableName zz_product_quality
*/
@TableName(value ="zz_product_quality")
@Data
public class ZzProductQuality implements Serializable {
/**
* 表ID
*/
@TableId(type = IdType.AUTO)
private Long zpqId;
/**
* 料号
*/
private String prdCode;
/**
* 品名
*/
private String prdName;
/**
* 生产批号
*/
private String manufactureBatchNo;
/**
* 质检报告地址
*/
private String qualityUrl;
/**
* 发货日期
*/
private Date shipDate;
/**
* 生产厂家名称
*/
private String manufacturersName;
/**
* 归属部门(工厂)编码
*/
private Long deptId;
/**
* 创建者
*/
private String createBy;
private Date createTime;
private String updateBy;
private Date updateTime;
/**
* 同步状态
* 0:未同步
* 1:已同步
* -1:无需同步
*/
private Integer syncStatus;
@TableField(exist = false)
private static final long serialVersionUID = 1L;
}
\ No newline at end of file
package com.sfa.job.domain.zzcenter.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.sfa.job.domain.zzcenter.entity.ZzProductQuality;
import org.springframework.stereotype.Repository;
/**
* @author a02200059
* @description 针对表【zz_product_quality(证照中心-质检报告表)】的数据库操作Mapper
* @createDate 2025-10-30 15:43:15
* @Entity com.sfa.operation.domain.zzhao.entity.ZzProductQuality
*/
@Repository
public interface ZzProductQualityMapper extends BaseMapper<ZzProductQuality> {
}
package com.sfa.job.pojo.zzcenter;
import lombok.Data;
import java.util.Date;
/**
* @author : liqiulin
* @date : 2025-10-30 16
* @describe :
*/
@Data
public class ZzProductQualityDto {
private Long zpqId;
/**
* 料号
*/
private String prdCode;
/**
* 品名
*/
private String prdName;
/**
* 生产批号
*/
private String manufactureBatchNo;
/**
* 质检报告地址
*/
private String qualityUrl;
/**
* 发货日期
*/
private Date shipDate;
/**
* 归属部门(工厂)编码
*/
private Long deptId;
/**
* 生产厂家名称
*/
private String manufacturersName;
/**
* 同步状态
* 0:未同步
* 1:已同步
* -1:无需同步
*/
private Integer syncStatus;
/**
* 创建者
*/
private String createBy;
private String updateBy;
}
package com.sfa.job.service.feishu; package com.sfa.job.service.feishu;
import com.alibaba.fastjson2.JSONObject; import com.alibaba.fastjson2.JSONObject;
import com.lark.oapi.service.vc.v1.model.MeetingSecuritySetting;
import com.sfa.common.core.utils.DateUtils; import com.sfa.common.core.utils.DateUtils;
import com.lark.oapi.service.corehr.v1.model.Offboarding; import com.lark.oapi.service.corehr.v1.model.Offboarding;
import com.lark.oapi.service.corehr.v2.model.*; import com.lark.oapi.service.corehr.v2.model.*;
...@@ -247,6 +248,7 @@ public class EventCallbackServiceImpl implements IEventCallbackService{ ...@@ -247,6 +248,7 @@ public class EventCallbackServiceImpl implements IEventCallbackService{
log.error("获取审批单字段ID失败:{}",approvalInfo); log.error("获取审批单字段ID失败:{}",approvalInfo);
// 调用封装的错误日志记录方法 // 调用封装的错误日志记录方法
recordErrorLog("FeiShu sync QinCe Price ", "FeiShu sync", "approvalInfo:" + approvalInfo, errorMsg); recordErrorLog("FeiShu sync QinCe Price ", "FeiShu sync", "approvalInfo:" + approvalInfo, errorMsg);
return; return;
} }
...@@ -261,6 +263,17 @@ public class EventCallbackServiceImpl implements IEventCallbackService{ ...@@ -261,6 +263,17 @@ public class EventCallbackServiceImpl implements IEventCallbackService{
fsInstanceId, productCode, productSpec, productPrice); fsInstanceId, productCode, productSpec, productPrice);
log.error(errorMsg); log.error(errorMsg);
// 调用封装的错误日志记录方法 // 调用封装的错误日志记录方法
if (StringUtils.isBlank(productCode)) {
productCode = "无";
}
if (productSpec == null ){
productSpec = "无";
}
if (productPrice == null){
productPrice = "无";
}
String message = String.format("审批单字段缺失:编码:%s,箱规:%s,供货价:%s", productCode, productSpec, productPrice);
FeiShuUtils.pustRoot(FeiShuUtil.syncpriceWebhook, message);
recordErrorLog("QinCe price sync", "QinCe price", "审批单ID:" + fsInstanceId, errorMsg); recordErrorLog("QinCe price sync", "QinCe price", "审批单ID:" + fsInstanceId, errorMsg);
return; return;
} }
...@@ -305,6 +318,8 @@ public class EventCallbackServiceImpl implements IEventCallbackService{ ...@@ -305,6 +318,8 @@ public class EventCallbackServiceImpl implements IEventCallbackService{
} catch (Exception e) { } catch (Exception e) {
String errorMsg = "处理勤策商品信息异常:" + e.getMessage(); String errorMsg = "处理勤策商品信息异常:" + e.getMessage();
log.error("处理勤策商品信息时发生异常,产品编码:{}", productCode, e); log.error("处理勤策商品信息时发生异常,产品编码:{}", productCode, e);
String message = String.format("[ERROR]处理勤策商品信息时发生异常,产品编码:%s", productCode);
FeiShuUtils.pustRoot(FeiShuUtil.syncpriceWebhook, message);
recordErrorLog("QinCe price sync error", "QinCe price", "产品编码:" + productCode, errorMsg); recordErrorLog("QinCe price sync error", "QinCe price", "产品编码:" + productCode, errorMsg);
} }
} }
......
package com.sfa.job.service.zzcenter;
import com.sfa.job.pojo.zzcenter.ZzProductQualityDto;
import java.util.List;
/**
* @Author: DouXinYu
* @Date: 2026-02-05 17:56
* @Description:
*/
public interface IZzProQualityService {
List<ZzProductQualityDto> queryNotSyncList(Integer status);
Integer updateSyncStatus(ZzProductQualityDto zzProductQualityDto);
}
package com.sfa.job.service.zzcenter.impl;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.sfa.job.domain.zzcenter.dao.IZzProductQualityDao;
import com.sfa.job.pojo.zzcenter.ZzProductQualityDto;
import com.sfa.job.service.zzcenter.IZzProQualityService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.List;
/**
* @Author: DouXinYu
* @Date: 2026-02-05 17:59
* @Description: 质检服务实现类
*/
@Service
@Slf4j
@DS("bi")
public class ZzProQualityServiceImpl implements IZzProQualityService {
@Autowired
IZzProductQualityDao zzProductQualityDao;
@Override
public List<ZzProductQualityDto> queryNotSyncList(Integer status) {
return zzProductQualityDao.selectListBySyncStatus(status);
}
@Override
public Integer updateSyncStatus(ZzProductQualityDto zzProductQualityDto) {
return zzProductQualityDao.updateSyncStatus(zzProductQualityDto);
}
}
...@@ -4,7 +4,10 @@ import cn.hutool.core.date.DatePattern; ...@@ -4,7 +4,10 @@ import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil; import cn.hutool.core.date.DateUtil;
import cn.hutool.http.HttpUtil; import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson2.JSONObject; import com.alibaba.fastjson2.JSONObject;
import com.sfa.job.domain.system.dao.ISysEventLogDao;
import com.sfa.job.pojo.response.SysEventLogDto;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
...@@ -27,6 +30,9 @@ public class T100Util { ...@@ -27,6 +30,9 @@ public class T100Util {
@Value("${t100.ent_id}") @Value("${t100.ent_id}")
private String entId; private String entId;
@Autowired
private ISysEventLogDao sysEventLogDao;
public String createOrUpdateDept(JSONObject deptJson,JSONObject deptT100){ public String createOrUpdateDept(JSONObject deptJson,JSONObject deptT100){
deptJson.put("host",getHost()); deptJson.put("host",getHost());
...@@ -115,4 +121,55 @@ public class T100Util { ...@@ -115,4 +121,55 @@ public class T100Util {
header.put("digi-key","f63b06af224e90ea3f9f08e0226fc91e"); header.put("digi-key","f63b06af224e90ea3f9f08e0226fc91e");
return header; return header;
} }
/**
* 创建产品质检报告
*/
public void createProQuality(JSONObject deptJson){
deptJson.put("host",getHost());
JSONObject datakey = new JSONObject();
datakey.put("CompanyId","BJHQ");
datakey.put("EntId",entId);
deptJson.put("datakey",datakey);
JSONObject service = new JSONObject();
service.put("name","ins_cimi001");
deptJson.put("service",service);
log.info("T100-A-质检报告传参:{}",deptJson);
String body = HttpUtil.createPost(url).body(deptJson.toString()).execute().body();
String msg = body.replaceAll("\n", "");
log.info("T100-A-质检报告结果:{}",msg);
String request = JSONObject.toJSONString(deptJson);
logEvent(request,body);
}
/**
* 修改产品质检报告
*/
public void updateProQuality(JSONObject deptJson){
deptJson.put("host",getHost());
JSONObject datakey = new JSONObject();
datakey.put("CompanyId","BJHQ");
datakey.put("EntId",entId);
deptJson.put("datakey",datakey);
JSONObject service = new JSONObject();
service.put("name","upd_cimi001");
deptJson.put("service",service);
log.info("T100-PUT-质检报告传参:{}",deptJson);
String body = HttpUtil.createPost(url).body(deptJson.toString()).execute().body();
String msg = body.replaceAll("\n", "");
log.info("T100-PUT-质检报告结果:{}",msg);
String request = JSONObject.toJSONString(deptJson);
logEvent(request,body);
}
private void logEvent(String request,String response) {
SysEventLogDto sysEventLog = new SysEventLogDto();
sysEventLog.setEventName("T100 Quality report");
sysEventLog.setEventGroup("T100 Quality");
sysEventLog.setRequestMsg(request);
sysEventLog.setResponseMsg(response);
sysEventLogDao.insert(sysEventLog);
}
} }
package com.sfa.job.xxljob.erp;
import com.alibaba.fastjson2.JSONObject;
import com.sfa.job.pojo.zzcenter.ZzProductQualityDto;
import com.sfa.job.service.zzcenter.IZzProQualityService;
import com.sfa.job.util.T100Util;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 质检报告推送T100定时任务(每小时执行)
* @Author: DouXinYu
* @Date: 2026-02-05 17:21
*/
@Component
@Slf4j
public class ZzQualityTask {
@Autowired
private IZzProQualityService zzProQualityService;
@Autowired
private T100Util t100Util;
// 单次接口调用重试次数(处理偶发故障)
private static final int RETRY_TIMES = 2;
// 重试间隔(毫秒),避免高频重试触发T100限流
private static final long RETRY_INTERVAL = 500;
/**
* 质检报告推送数据到T100 每小时执行一次: * 0 0/1 * * * ?
*/
@XxlJob("ZzQualityToT100Job")
public void execute() {
XxlJobHelper.log("======================== 未同步质检报告推送数据到T100 开始 ================================");
// 统计本次任务执行结果,运维一眼可知
AtomicInteger totalCount = new AtomicInteger(0);
AtomicInteger successCount = new AtomicInteger(0);
AtomicInteger failCount = new AtomicInteger(0);
try {
// 获取未同步的质检报告数据
List<ZzProductQualityDto> zzProductQualityDtoList = zzProQualityService.queryNotSyncList(0);
totalCount.set(zzProductQualityDtoList.size());
XxlJobHelper.log("本次查询到未同步质检报告数据共【{}】条", totalCount.get());
if (zzProductQualityDtoList.isEmpty()) {
XxlJobHelper.log("无未同步数据,任务直接结束");
return;
}
// 循环处理,复用JSONObject减少创建(小优化)
JSONObject deptJson = new JSONObject();
JSONObject dataMap = new JSONObject();
for (ZzProductQualityDto dto : zzProductQualityDtoList) {
try {
dataMap.clear();
deptJson.clear();
dataMap.put("imjyuc001", dto.getPrdCode());
dataMap.put("imjyuc002", dto.getManufactureBatchNo());
dataMap.put("imjyuc003", dto.getQualityUrl());
dataMap.put("imjyuc004", dto.getManufacturersName());
deptJson.putObject("payload").putObject("std_data").putObject("parameter").putArray("data").add(dataMap);
// 加重试机制,处理偶发故障
boolean pushSuccess = retryPush(deptJson);
if (pushSuccess) {
dto.setSyncStatus(1);
zzProQualityService.updateSyncStatus(dto);
successCount.incrementAndGet();
XxlJobHelper.log("推送T100成功,料号:{},批号:{}", dto.getPrdCode(), dto.getManufactureBatchNo());
} else {
failCount.incrementAndGet();
log.error("推送T100失败,多次重试后仍未成功,数据:{}", dto);
}
} catch (Exception e) {
failCount.incrementAndGet();
// 核心:打印完整堆栈,保留异常根因,方便排查
log.error("处理单条质检报告数据时发生异常,数据:{}", dto, e);
}
}
} catch (Exception e) {
// 任务整体异常,标记为失败,XXL-Job管理台会告警
XxlJobHelper.handleFail("质检报告推送T100任务整体执行异常:" + e.getMessage());
log.error("质检报告推送T100任务整体执行异常", e);
return;
}
XxlJobHelper.log("======================== 未同步质检报告推送数据到T100 结束 ================================");
XxlJobHelper.log("本次任务执行统计:总条数【{}】,成功【{}】,失败【{}】",
totalCount.get(), successCount.get(), failCount.get());
}
/**
* 带重试的T100推送方法,处理偶发故障
*/
private boolean retryPush(JSONObject deptJson) {
for (int i = 0; i < RETRY_TIMES; i++) {
try {
// 调用原有T100方法
t100Util.createProQuality(deptJson);
return true;
} catch (Exception e) {
// 重试时打印warn日志,区分永久失败和临时重试
log.warn("推送T100第【{}】次重试失败,错误信息:{}", i + 1, e.getMessage());
// 最后一次重试失败,直接返回false
if (i == RETRY_TIMES - 1) {
return false;
}
try {
Thread.sleep(RETRY_INTERVAL);
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
log.error("重试间隔时线程被中断", ie);
return false;
}
}
}
return false;
}
}
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.sfa.operation.domain.zzhao.mapper.ZzProductQualityMapper">
<resultMap id="ZzProductQualityBase" type="com.sfa.job.domain.zzcenter.entity.ZzProductQuality">
<id property="zpqId" column="zpq_id" jdbcType="BIGINT"/>
<result property="prdCode" column="prd_code" jdbcType="VARCHAR"/>
<result property="prdName" column="prd_name" jdbcType="VARCHAR"/>
<result property="manufactureBatchNo" column="manufacture_batch_no" jdbcType="VARCHAR"/>
<result property="qualityUrl" column="quality_url" jdbcType="VARCHAR"/>
<result property="shipDate" column="ship_date" jdbcType="TIMESTAMP"/>
<result property="manufacturersName" column="manufacturers_name" jdbcType="VARCHAR"/>
<result property="createBy" column="create_by" jdbcType="VARCHAR"/>
<result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
<result property="syncStatus" column="sync_status" jdbcType="INTEGER"/>
</resultMap>
</mapper>
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论