Compare commits

..

2 Commits

Author SHA1 Message Date
van
042068ccf1 1 2026-04-10 01:00:10 +08:00
van
52d0adfc85 1 2026-04-10 00:57:31 +08:00
10 changed files with 126 additions and 6 deletions

View File

@@ -8,6 +8,7 @@ import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.jarvis.config.JarvisGoofishProperties; import com.ruoyi.jarvis.config.JarvisGoofishProperties;
import com.ruoyi.jarvis.domain.ErpGoofishOrder; import com.ruoyi.jarvis.domain.ErpGoofishOrder;
import com.ruoyi.jarvis.domain.ErpGoofishOrderEventLog; import com.ruoyi.jarvis.domain.ErpGoofishOrderEventLog;
import com.ruoyi.jarvis.domain.ErpGoofishOrderEventLogQuery;
import com.ruoyi.jarvis.service.IErpGoofishOrderService; import com.ruoyi.jarvis.service.IErpGoofishOrderService;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
@@ -27,6 +28,17 @@ public class ErpGoofishOrderController extends BaseController {
@Resource @Resource
private JarvisGoofishProperties goofishProperties; private JarvisGoofishProperties goofishProperties;
/**
* 订单变更日志全表检索(跨订单排查),须配置在 /{id} 之前避免歧义;对应日志标记 [goofish-order-event]
*/
@PreAuthorize("@ss.hasPermi('jarvis:erpGoofishOrder:list')")
@GetMapping("/eventLog/list")
public TableDataInfo eventLogList(ErpGoofishOrderEventLogQuery query) {
startPage();
List<ErpGoofishOrderEventLog> list = erpGoofishOrderService.selectEventLogList(query);
return getDataTable(list);
}
@PreAuthorize("@ss.hasPermi('jarvis:erpGoofishOrder:list')") @PreAuthorize("@ss.hasPermi('jarvis:erpGoofishOrder:list')")
@GetMapping("/list") @GetMapping("/list")
public TableDataInfo list(ErpGoofishOrder query) { public TableDataInfo list(ErpGoofishOrder query) {

View File

@@ -2,6 +2,7 @@
-- 说明:菜单需在「系统管理-菜单管理」中自行新增,组件路径示例: -- 说明:菜单需在「系统管理-菜单管理」中自行新增,组件路径示例:
-- 配置中心 system/goofish/erpOpenConfig/index -- 配置中心 system/goofish/erpOpenConfig/index
-- 订单跟踪 system/goofish/erpGoofishOrder/index -- 订单跟踪 system/goofish/erpGoofishOrder/index
-- 变更日志(跨单排查,对接 GET /jarvis/erpGoofishOrder/eventLog/listsystem/goofish/erpGoofishEventLog/index
CREATE TABLE IF NOT EXISTS erp_open_config ( CREATE TABLE IF NOT EXISTS erp_open_config (
id bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', id bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
@@ -87,6 +88,8 @@ CREATE TABLE IF NOT EXISTS erp_goofish_order_event_log (
-- 父菜单系统管理下新增目录「闲管家ERP」 -- 父菜单系统管理下新增目录「闲管家ERP」
-- 子菜单1组件 system/goofish/erpOpenConfig/index 权限前缀 jarvis:erpOpenConfig -- 子菜单1组件 system/goofish/erpOpenConfig/index 权限前缀 jarvis:erpOpenConfig
-- 子菜单2组件 system/goofish/erpGoofishOrder/index 权限前缀 jarvis:erpGoofishOrder -- 子菜单2组件 system/goofish/erpGoofishOrder/index 权限前缀 jarvis:erpGoofishOrder
-- 子菜单3组件 system/goofish/erpGoofishEventLog/index 权限沿用 jarvis:erpGoofishOrder:list 即可(仅列表查询)
-- 路由地址建议与订单页同级,如订单为 …/erpGoofishOrder 则本页 …/erpGoofishEventLog订单页「变更日志排查」按钮依赖此规则
-- 按钮权限示例: -- 按钮权限示例:
-- jarvis:erpOpenConfig:list,query,add,edit,remove -- jarvis:erpOpenConfig:list,query,add,edit,remove
-- jarvis:erpGoofishOrder:list,query,edit -- jarvis:erpGoofishOrder:list,query,edit

View File

@@ -18,7 +18,7 @@ public class ErpGoofishOrderEventLog {
private String orderNo; private String orderNo;
/** ORDER_SYNC / LOGISTICS_SYNC / SHIP */ /** ORDER_SYNC / LOGISTICS_SYNC / SHIP */
private String eventType; private String eventType;
/** NOTIFY、LIST、DETAIL_REFRESH、UPSERT、REDIS_WAYBILL、AUTO_SHIP 等 */ /** NOTIFY、LIST、DETAIL_REFRESH、JD_LOGISTICS_PUSH、REDIS_WAYBILL、AUTO_SHIP 等 */
private String source; private String source;
private String message; private String message;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")

View File

@@ -0,0 +1,21 @@
package com.ruoyi.jarvis.domain;
import com.ruoyi.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 闲管家订单变更日志(全表检索,用于排查)
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class ErpGoofishOrderEventLogQuery extends BaseEntity {
private Long orderId;
private String appKey;
private String orderNo;
private String eventType;
private String source;
/** 模糊匹配 message */
private String messageKeyword;
}

View File

@@ -1,6 +1,7 @@
package com.ruoyi.jarvis.mapper; package com.ruoyi.jarvis.mapper;
import com.ruoyi.jarvis.domain.ErpGoofishOrderEventLog; import com.ruoyi.jarvis.domain.ErpGoofishOrderEventLog;
import com.ruoyi.jarvis.domain.ErpGoofishOrderEventLogQuery;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
import java.util.List; import java.util.List;
@@ -10,4 +11,6 @@ public interface ErpGoofishOrderEventLogMapper {
int insert(ErpGoofishOrderEventLog row); int insert(ErpGoofishOrderEventLog row);
List<ErpGoofishOrderEventLog> selectByOrderId(@Param("orderId") Long orderId); List<ErpGoofishOrderEventLog> selectByOrderId(@Param("orderId") Long orderId);
List<ErpGoofishOrderEventLog> selectLogList(ErpGoofishOrderEventLogQuery query);
} }

View File

@@ -3,6 +3,7 @@ package com.ruoyi.jarvis.service;
import com.alibaba.fastjson2.JSONObject; import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.jarvis.domain.ErpGoofishOrder; import com.ruoyi.jarvis.domain.ErpGoofishOrder;
import com.ruoyi.jarvis.domain.ErpGoofishOrderEventLog; import com.ruoyi.jarvis.domain.ErpGoofishOrderEventLog;
import com.ruoyi.jarvis.domain.ErpGoofishOrderEventLogQuery;
import java.util.List; import java.util.List;
@@ -41,6 +42,12 @@ public interface IErpGoofishOrderService {
*/ */
void notifyJdWaybillReady(Long jdOrderId); void notifyJdWaybillReady(Long jdOrderId);
/** 京东物流服务在写 Redis / 企微货主推送后、触发闲鱼同步前记一笔source=JD_LOGISTICS_PUSH。 */
void traceJdLogisticsPushForGoofish(Long jdOrderId, String waybillNo, String summary);
/** 订单状态 / 物流 / 发货 变更日志(新→旧) */ /** 订单状态 / 物流 / 发货 变更日志(新→旧) */
List<ErpGoofishOrderEventLog> listEventLogsByOrderId(Long orderId); List<ErpGoofishOrderEventLog> listEventLogsByOrderId(Long orderId);
/** 全表分页检索(排查用,配合 PageHelper */
List<ErpGoofishOrderEventLog> selectEventLogList(ErpGoofishOrderEventLogQuery query);
} }

View File

@@ -28,6 +28,9 @@ public class GoofishOrderChangeLogger {
public static final String TYPE_LOGISTICS = "LOGISTICS_SYNC"; public static final String TYPE_LOGISTICS = "LOGISTICS_SYNC";
public static final String TYPE_SHIP = "SHIP"; public static final String TYPE_SHIP = "SHIP";
/** 京东物流扫描服务Redis + 企微货主推送链路(见 LogisticsServiceImpl不再二次走 wxSend 闲鱼应用避免重复打扰 */
public static final String SOURCE_JD_LOGISTICS_PUSH = "JD_LOGISTICS_PUSH";
@Resource @Resource
private ErpGoofishOrderEventLogMapper erpGoofishOrderEventLogMapper; private ErpGoofishOrderEventLogMapper erpGoofishOrderEventLogMapper;
@@ -54,6 +57,9 @@ public class GoofishOrderChangeLogger {
return; return;
} }
log.info("[goofish-order-event] orderId={} orderNo={} type={} source={} {}", orderId, orderNo, eventType, source, msg); log.info("[goofish-order-event] orderId={} orderNo={} type={} source={} {}", orderId, orderNo, eventType, source, msg);
if (SOURCE_JD_LOGISTICS_PUSH.equals(source)) {
return;
}
try { try {
wxSendGoofishNotifyClient.notifyGoofishEvent(orderNo, eventType, source, msg); wxSendGoofishNotifyClient.notifyGoofishEvent(orderNo, eventType, source, msg);
} catch (Exception ex) { } catch (Exception ex) {

View File

@@ -5,6 +5,7 @@ import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.jarvis.config.JarvisGoofishProperties; import com.ruoyi.jarvis.config.JarvisGoofishProperties;
import com.ruoyi.jarvis.domain.ErpGoofishOrder; import com.ruoyi.jarvis.domain.ErpGoofishOrder;
import com.ruoyi.jarvis.domain.ErpGoofishOrderEventLog; import com.ruoyi.jarvis.domain.ErpGoofishOrderEventLog;
import com.ruoyi.jarvis.domain.ErpGoofishOrderEventLogQuery;
import com.ruoyi.jarvis.domain.ErpOpenConfig; import com.ruoyi.jarvis.domain.ErpOpenConfig;
import com.ruoyi.jarvis.dto.GoofishNotifyMessage; import com.ruoyi.jarvis.dto.GoofishNotifyMessage;
import com.ruoyi.jarvis.mapper.ErpGoofishOrderEventLogMapper; import com.ruoyi.jarvis.mapper.ErpGoofishOrderEventLogMapper;
@@ -12,6 +13,7 @@ import com.ruoyi.jarvis.mapper.ErpGoofishOrderMapper;
import com.ruoyi.jarvis.service.IErpGoofishOrderService; import com.ruoyi.jarvis.service.IErpGoofishOrderService;
import com.ruoyi.jarvis.service.IErpOpenConfigService; import com.ruoyi.jarvis.service.IErpOpenConfigService;
import com.ruoyi.jarvis.service.goofish.GoofishNotifyAsyncFacade; import com.ruoyi.jarvis.service.goofish.GoofishNotifyAsyncFacade;
import com.ruoyi.jarvis.service.goofish.GoofishOrderChangeLogger;
import com.ruoyi.jarvis.service.goofish.GoofishOrderPipeline; import com.ruoyi.jarvis.service.goofish.GoofishOrderPipeline;
import org.apache.rocketmq.spring.core.RocketMQTemplate; import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.ObjectProvider;
@@ -46,6 +48,9 @@ public class ErpGoofishOrderServiceImpl implements IErpGoofishOrderService {
@Resource @Resource
private IErpOpenConfigService erpOpenConfigService; private IErpOpenConfigService erpOpenConfigService;
@Resource
private GoofishOrderChangeLogger goofishOrderChangeLogger;
@Override @Override
public void publishOrProcessNotify(String appid, Long timestamp, JSONObject body) { public void publishOrProcessNotify(String appid, Long timestamp, JSONObject body) {
RocketMQTemplate mq = rocketMQTemplate.getIfAvailable(); RocketMQTemplate mq = rocketMQTemplate.getIfAvailable();
@@ -166,6 +171,32 @@ public class ErpGoofishOrderServiceImpl implements IErpGoofishOrderService {
} }
} }
@Override
public void traceJdLogisticsPushForGoofish(Long jdOrderId, String waybillNo, String summary) {
if (jdOrderId == null || goofishOrderChangeLogger == null) {
return;
}
ErpGoofishOrder query = new ErpGoofishOrder();
query.setJdOrderId(jdOrderId);
List<ErpGoofishOrder> list = erpGoofishOrderMapper.selectList(query);
if (list == null || list.isEmpty()) {
return;
}
String wb = waybillNo != null ? waybillNo.trim() : "";
String sum = summary != null ? summary : "";
String msg = "jdOrderId=" + jdOrderId + " waybill=" + wb + "" + sum;
if (msg.length() > 1000) {
msg = msg.substring(0, 999) + "";
}
for (ErpGoofishOrder row : list) {
if (row.getId() == null) {
continue;
}
goofishOrderChangeLogger.append(row.getId(), row.getAppKey(), row.getOrderNo(),
GoofishOrderChangeLogger.TYPE_LOGISTICS, GoofishOrderChangeLogger.SOURCE_JD_LOGISTICS_PUSH, msg);
}
}
@Override @Override
public List<ErpGoofishOrderEventLog> listEventLogsByOrderId(Long orderId) { public List<ErpGoofishOrderEventLog> listEventLogsByOrderId(Long orderId) {
if (orderId == null) { if (orderId == null) {
@@ -174,4 +205,13 @@ public class ErpGoofishOrderServiceImpl implements IErpGoofishOrderService {
List<ErpGoofishOrderEventLog> list = erpGoofishOrderEventLogMapper.selectByOrderId(orderId); List<ErpGoofishOrderEventLog> list = erpGoofishOrderEventLogMapper.selectByOrderId(orderId);
return list != null ? list : Collections.emptyList(); return list != null ? list : Collections.emptyList();
} }
@Override
public List<ErpGoofishOrderEventLog> selectEventLogList(ErpGoofishOrderEventLogQuery query) {
if (query == null) {
query = new ErpGoofishOrderEventLogQuery();
}
List<ErpGoofishOrderEventLog> list = erpGoofishOrderEventLogMapper.selectLogList(query);
return list != null ? list : Collections.emptyList();
}
} }

View File

@@ -219,9 +219,13 @@ public class LogisticsServiceImpl implements ILogisticsService {
} }
} }
/** 京东单已写入 Redis 运单后,联动闲鱼单同步并发货(失败不影响物流主流程) */ /**
private void safeNotifyGoofishShip(Long jdOrderId) { * 京东单已写入 Redis 运单后,联动闲鱼单同步并发货(失败不影响物流主流程)。
* 若存在关联闲鱼单,会先写入事件来源 JD_LOGISTICS_PUSH便于与 REDIS_WAYBILL / AUTO_SHIP 对照。
*/
private void safeNotifyGoofishShip(Long jdOrderId, String waybillNo, String traceSummary) {
try { try {
erpGoofishOrderService.traceJdLogisticsPushForGoofish(jdOrderId, waybillNo, traceSummary);
erpGoofishOrderService.notifyJdWaybillReady(jdOrderId); erpGoofishOrderService.notifyJdWaybillReady(jdOrderId);
} catch (Exception e) { } catch (Exception e) {
logger.warn("闲鱼发货联动异常 jdOrderId={} err={}", jdOrderId, e.toString()); logger.warn("闲鱼发货联动异常 jdOrderId={} err={}", jdOrderId, e.toString());
@@ -388,7 +392,8 @@ public class LogisticsServiceImpl implements ILogisticsService {
logger.info("订单运单号已存在且一致,说明之前已推送过,跳过重复推送 - 订单ID: {}, waybill_no: {}", orderId, waybillNo); logger.info("订单运单号已存在且一致,说明之前已推送过,跳过重复推送 - 订单ID: {}, waybill_no: {}", orderId, waybillNo);
// 更新过期时间,确保记录不会过期 // 更新过期时间,确保记录不会过期
stringRedisTemplate.opsForValue().set(redisKey, waybillNo, 30, TimeUnit.DAYS); stringRedisTemplate.opsForValue().set(redisKey, waybillNo, 30, TimeUnit.DAYS);
safeNotifyGoofishShip(orderId); safeNotifyGoofishShip(orderId, waybillNo,
"Redis 运单与本次一致,跳过重复企微推送;已刷新 TTL随后触发闲鱼同步");
return true; return true;
} }
@@ -406,7 +411,8 @@ public class LogisticsServiceImpl implements ILogisticsService {
logger.info("订单创建时间较早({}且Redis中无记录但已获取到运单号视为之前已推送过直接标记为已处理跳过推送 - 订单ID: {}, waybill_no: {}", logger.info("订单创建时间较早({}且Redis中无记录但已获取到运单号视为之前已推送过直接标记为已处理跳过推送 - 订单ID: {}, waybill_no: {}",
order.getCreateTime(), orderId, waybillNo); order.getCreateTime(), orderId, waybillNo);
stringRedisTemplate.opsForValue().set(redisKey, waybillNo, 30, TimeUnit.DAYS); stringRedisTemplate.opsForValue().set(redisKey, waybillNo, 30, TimeUnit.DAYS);
safeNotifyGoofishShip(orderId); safeNotifyGoofishShip(orderId, waybillNo,
"老单兜底:直写 Redis跳过企微随后触发闲鱼同步");
return true; return true;
} }
} }
@@ -433,7 +439,9 @@ public class LogisticsServiceImpl implements ILogisticsService {
// 更新过期时间,确保记录不会过期 // 更新过期时间,确保记录不会过期
stringRedisTemplate.opsForValue().set(redisKey, waybillNo, 30, TimeUnit.DAYS); stringRedisTemplate.opsForValue().set(redisKey, waybillNo, 30, TimeUnit.DAYS);
} }
safeNotifyGoofishShip(orderId); safeNotifyGoofishShip(orderId, waybillNo,
"企微货主推送成功;" + (logisticsLinkUpdated ? "物流链接已更新;" : "物流链接未变;")
+ "Redis 已写入;随后触发闲鱼同步");
// 记录最终处理结果 // 记录最终处理结果
if (logisticsLinkUpdated) { if (logisticsLinkUpdated) {

View File

@@ -26,4 +26,24 @@
where order_id = #{orderId} where order_id = #{orderId}
order by id desc order by id desc
</select> </select>
<select id="selectLogList" parameterType="com.ruoyi.jarvis.domain.ErpGoofishOrderEventLogQuery" resultMap="ErpGoofishOrderEventLogResult">
select id, order_id, app_key, order_no, event_type, source, message, create_time
from erp_goofish_order_event_log
<where>
<if test="orderId != null">and order_id = #{orderId}</if>
<if test="appKey != null and appKey != ''">and app_key = #{appKey}</if>
<if test="orderNo != null and orderNo != ''">and order_no like concat('%', #{orderNo}, '%')</if>
<if test="eventType != null and eventType != ''">and event_type = #{eventType}</if>
<if test="source != null and source != ''">and source like concat('%', #{source}, '%')</if>
<if test="messageKeyword != null and messageKeyword != ''">and message like concat('%', #{messageKeyword}, '%')</if>
<if test="params != null and params.beginTime != null and params.beginTime != ''">
and create_time &gt;= concat(#{params.beginTime}, ' 00:00:00')
</if>
<if test="params != null and params.endTime != null and params.endTime != ''">
and create_time &lt;= concat(#{params.endTime}, ' 23:59:59')
</if>
</where>
order by id desc
</select>
</mapper> </mapper>