1
This commit is contained in:
@@ -45,6 +45,9 @@ public interface IErpGoofishOrderService {
|
||||
/** 京东物流服务在写 Redis / 企微货主推送后、触发闲鱼同步前记一笔(source=JD_LOGISTICS_PUSH)。 */
|
||||
void traceJdLogisticsPushForGoofish(Long jdOrderId, String waybillNo, String summary);
|
||||
|
||||
/** 是否存在关联本京东单的闲管家订单(用于物流企微走闲鱼自建应用)。 */
|
||||
boolean hasLinkedGoofishOrder(Long jdOrderId);
|
||||
|
||||
/** 订单状态 / 物流 / 发货 变更日志(新→旧) */
|
||||
List<ErpGoofishOrderEventLog> listEventLogsByOrderId(Long orderId);
|
||||
|
||||
|
||||
@@ -28,7 +28,9 @@ public class GoofishOrderChangeLogger {
|
||||
public static final String TYPE_LOGISTICS = "LOGISTICS_SYNC";
|
||||
public static final String TYPE_SHIP = "SHIP";
|
||||
|
||||
/** 京东物流扫描服务:Redis + 企微货主推送链路(见 LogisticsServiceImpl),不再二次走 wxSend 闲鱼应用避免重复打扰 */
|
||||
/**
|
||||
* 京东物流扫描:货主通知已由 LogisticsServiceImpl 走闲鱼自建应用或 PDD;此处仅落库,避免再调 wxSend 重复推送。
|
||||
*/
|
||||
public static final String SOURCE_JD_LOGISTICS_PUSH = "JD_LOGISTICS_PUSH";
|
||||
|
||||
@Resource
|
||||
|
||||
@@ -171,6 +171,17 @@ public class ErpGoofishOrderServiceImpl implements IErpGoofishOrderService {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasLinkedGoofishOrder(Long jdOrderId) {
|
||||
if (jdOrderId == null) {
|
||||
return false;
|
||||
}
|
||||
ErpGoofishOrder query = new ErpGoofishOrder();
|
||||
query.setJdOrderId(jdOrderId);
|
||||
List<ErpGoofishOrder> list = erpGoofishOrderMapper.selectList(query);
|
||||
return list != null && !list.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void traceJdLogisticsPushForGoofish(Long jdOrderId, String waybillNo, String summary) {
|
||||
if (jdOrderId == null || goofishOrderChangeLogger == null) {
|
||||
|
||||
@@ -9,6 +9,7 @@ import com.ruoyi.jarvis.mapper.WeComShareLinkLogisticsJobMapper;
|
||||
import com.ruoyi.jarvis.service.IErpGoofishOrderService;
|
||||
import com.ruoyi.jarvis.service.ILogisticsService;
|
||||
import com.ruoyi.jarvis.service.IJDOrderService;
|
||||
import com.ruoyi.jarvis.wecom.WxSendGoofishNotifyClient;
|
||||
import com.ruoyi.system.service.ISysConfigService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -85,6 +86,9 @@ public class LogisticsServiceImpl implements ILogisticsService {
|
||||
|
||||
@Resource
|
||||
private IErpGoofishOrderService erpGoofishOrderService;
|
||||
|
||||
@Resource
|
||||
private WxSendGoofishNotifyClient wxSendGoofishNotifyClient;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
@@ -847,8 +851,23 @@ public class LogisticsServiceImpl implements ILogisticsService {
|
||||
// 运单号
|
||||
pushContent.append("运单号:").append("\n").append("\n").append("\n").append("\n").append(waybillNo).append("\n");
|
||||
|
||||
|
||||
// 调用企业微信推送接口
|
||||
boolean useGoofishWecom = erpGoofishOrderService.hasLinkedGoofishOrder(order.getId())
|
||||
|| (distributionMark != null && distributionMark.contains("闲鱼"));
|
||||
if (useGoofishWecom) {
|
||||
String touserGoofish = getTouserByDistributionMark(distributionMark);
|
||||
String fullText = "JD物流信息推送\n" + pushContent;
|
||||
logger.info("闲鱼关联或分销含「闲鱼」:尝试企微闲鱼自建应用 - 订单ID: {}, 分销标识: {}, 接收人: {}",
|
||||
order.getId(), distributionMark,
|
||||
StringUtils.hasText(touserGoofish) ? touserGoofish : "(jarvis.wecom.goofish-notify-touser)");
|
||||
if (wxSendGoofishNotifyClient.pushGoofishAgentText(touserGoofish, fullText)) {
|
||||
logger.info("企微闲鱼应用推送成功 - 订单ID: {}, 订单号: {}, waybill_no: {}",
|
||||
order.getId(), order.getOrderId(), waybillNo);
|
||||
return true;
|
||||
}
|
||||
logger.warn("企微闲鱼应用推送失败或未配置 wxSend,回退 PDD 通道 - 订单ID: {}", order.getId());
|
||||
}
|
||||
|
||||
// 调用企业微信推送接口(PDD 自建应用)
|
||||
JSONObject pushParam = new JSONObject();
|
||||
pushParam.put("title", "JD物流信息推送");
|
||||
pushParam.put("text", pushContent.toString());
|
||||
|
||||
@@ -5,15 +5,18 @@ import com.ruoyi.jarvis.service.IJDOrderService;
|
||||
import com.ruoyi.jarvis.service.ILogisticsService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 物流信息扫描定时任务
|
||||
* 每15分钟扫描一次分销标记为F或PDD的订单(最近30天),获取物流信息并推送;结束后处理企微分享链 adhoc 队列
|
||||
* 按配置周期(默认每 20 分钟)扫描分销标记为 F/PDD 等的订单(最近 30 天),拉物流并推送;
|
||||
* 结束后处理企微分享链 adhoc 队列。
|
||||
*/
|
||||
@Component
|
||||
public class LogisticsScanTask {
|
||||
@@ -25,11 +28,18 @@ public class LogisticsScanTask {
|
||||
@Resource
|
||||
private ILogisticsService logisticsService;
|
||||
|
||||
/** 每条订单处理后的间隔(毫秒),减轻下游物流 HTTP 压力;0 表示不睡眠 */
|
||||
@Value("${jarvis.server.logistics.scan.order-delay-ms:250}")
|
||||
private long orderDelayMs;
|
||||
|
||||
/** 单轮最多处理的订单数,0 表示不限制(候选很多时可限制单轮耗时) */
|
||||
@Value("${jarvis.server.logistics.scan.max-orders-per-round:0}")
|
||||
private int maxOrdersPerRound;
|
||||
|
||||
/**
|
||||
* 定时任务:每15分钟执行一次(与 @Scheduled 中 cron 一致)
|
||||
* 只扫描最近30天的订单
|
||||
* 只扫描最近 30 天的订单(SQL 固定);周期与单轮上限见 jarvis.server.logistics.scan.*
|
||||
*/
|
||||
@Scheduled(cron = "0 */15 * * * ?")
|
||||
@Scheduled(cron = "${jarvis.server.logistics.scan.cron:0 */20 * * * ?}")
|
||||
public void scanAndFetchLogistics() {
|
||||
long t0 = System.currentTimeMillis();
|
||||
int orderCandidates = 0;
|
||||
@@ -47,8 +57,14 @@ public class LogisticsScanTask {
|
||||
if (orders == null || orders.isEmpty()) {
|
||||
logger.info("订单扫描:候选 0 条(最近30天 F/PDD 有物流链)");
|
||||
} else {
|
||||
int totalFromDb = orders.size();
|
||||
if (maxOrdersPerRound > 0 && orders.size() > maxOrdersPerRound) {
|
||||
logger.info("订单扫描:库中候选 {} 条,本轮按 max-orders-per-round={} 仅处理前 {} 条(余下轮次继续)",
|
||||
totalFromDb, maxOrdersPerRound, maxOrdersPerRound);
|
||||
orders = new ArrayList<>(orders.subList(0, maxOrdersPerRound));
|
||||
}
|
||||
orderCandidates = orders.size();
|
||||
logger.info("订单扫描:候选 {} 条(最近30天 F/PDD 有物流链)", orderCandidates);
|
||||
logger.info("订单扫描:本轮处理列表 {} 条(最近30天 F/PDD 有物流链)", orderCandidates);
|
||||
|
||||
for (JDOrder order : orders) {
|
||||
try {
|
||||
@@ -57,7 +73,7 @@ public class LogisticsScanTask {
|
||||
continue;
|
||||
}
|
||||
|
||||
logger.info("订单扫描:处理中 id={} orderId={} mark={}",
|
||||
logger.debug("订单扫描:处理中 id={} orderId={} mark={}",
|
||||
order.getId(), order.getOrderId(), order.getDistributionMark());
|
||||
|
||||
boolean success = logisticsService.fetchLogisticsAndPush(order);
|
||||
@@ -70,7 +86,9 @@ public class LogisticsScanTask {
|
||||
logger.warn("订单扫描:未成功 id={} orderId={}", order.getId(), order.getOrderId());
|
||||
}
|
||||
|
||||
Thread.sleep(500);
|
||||
if (orderDelayMs > 0) {
|
||||
Thread.sleep(orderDelayMs);
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
logger.error("定时任务被中断", e);
|
||||
Thread.currentThread().interrupt();
|
||||
|
||||
@@ -70,6 +70,37 @@ public class WxSendGoofishNotifyClient {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 京东物流扫描等:全文发往企微「闲鱼」自建应用(wxSend qywx.app.goofishAgentId)。
|
||||
*
|
||||
* @param optionalToUser 非空时用与 logistics.push.touser.* 相同的成员 ID(逗号/| 亦可);空则用 goofish-notify-touser
|
||||
* @return HTTP 2xx 为 true;未配置密钥或 toUser 为空返回 false
|
||||
*/
|
||||
public boolean pushGoofishAgentText(String optionalToUser, String content) {
|
||||
if (!StringUtils.hasText(wxsendBaseUrl) || !StringUtils.hasText(goofishPushSecret)) {
|
||||
log.debug("wxSend 闲鱼应用物流推送跳过:未配置 wxsend-base-url 或 goofish-push-secret");
|
||||
return false;
|
||||
}
|
||||
String rawTouser = StringUtils.hasText(optionalToUser) ? optionalToUser : goofishNotifyTouser;
|
||||
String toUser = buildTouserParam(rawTouser);
|
||||
if (!StringUtils.hasText(toUser)) {
|
||||
log.warn("wxSend 闲鱼应用物流推送跳过:无接收人(请配置 jarvis.wecom.goofish-notify-touser 或 logistics.push.touser)");
|
||||
return false;
|
||||
}
|
||||
String text = content != null ? content : "";
|
||||
if (text.length() > CONTENT_MAX) {
|
||||
text = text.substring(0, CONTENT_MAX - 1) + "…";
|
||||
}
|
||||
try {
|
||||
String base = normalizeBase(wxsendBaseUrl);
|
||||
String url = base + "/wecom/goofish-active-push";
|
||||
return postJsonReturnsOk(url, toUser, text);
|
||||
} catch (Exception e) {
|
||||
log.warn("wxSend goofish-active-push 物流全文失败 err={}", e.toString());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static String buildContent(String orderNo, String eventType, String source, String message) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("【闲鱼订单】").append(orderNo != null ? orderNo : "-").append("\n");
|
||||
@@ -120,6 +151,10 @@ public class WxSendGoofishNotifyClient {
|
||||
}
|
||||
|
||||
private void postJson(String url, String toUser, String content) throws Exception {
|
||||
postJsonReturnsOk(url, toUser, content);
|
||||
}
|
||||
|
||||
private boolean postJsonReturnsOk(String url, String toUser, String content) throws Exception {
|
||||
JSONObject body = new JSONObject();
|
||||
body.put("toUser", toUser);
|
||||
body.put("content", content);
|
||||
@@ -141,9 +176,10 @@ public class WxSendGoofishNotifyClient {
|
||||
String resp = readAll(is);
|
||||
if (code < 200 || code >= 300) {
|
||||
log.warn("wxSend goofish-active-push HTTP {} body={}", code, resp);
|
||||
} else {
|
||||
log.debug("wxSend goofish-active-push OK http={} resp={}", code, resp);
|
||||
return false;
|
||||
}
|
||||
log.debug("wxSend goofish-active-push OK http={} resp={}", code, resp);
|
||||
return true;
|
||||
} finally {
|
||||
if (conn != null) {
|
||||
conn.disconnect();
|
||||
|
||||
Reference in New Issue
Block a user