修复回调问题,通道问题

This commit is contained in:
zjf committed 2026-02-22 18:28:34 +08:00
1 parent 75c942c5c8
commit 6ba8b4fa00
5 files changed
+104 -65

No files matched your search

@@ -406,14 +406,14 @@ public class ChannelServiceImpl implements ChannelService {
throw exception0(1_008_015_001, "出货失败!原因: " + body.getMsg());
}
} else {
deviceLog.setDeviceStatus(501);
deviceLog.setDeviceStatus(99);
deviceLog.setContent("操作失败!原因: 请求出货响应为空");
productDeviceLogService.createDeviceLog(deviceLog);
throw exception(CHANNEL_ERROR);
}
/*} catch (Exception e) {
System.err.println("请求异常: " + e.getMessage());
deviceLog.setDeviceStatus(500);
deviceLog.setDeviceStatus(99);
deviceLog.setContent("请求异常: " + e.getMessage());
productDeviceLogService.createDeviceLog(deviceLog);
throw exception0(1_008_016_001, "请求异常: " + e.getMessage());
@@ -30,7 +30,7 @@ import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
import cn.iocoder.yudao.module.product.enums.sku.ProductSkuPurchaseBizTypeEnum;
import cn.iocoder.yudao.module.product.enums.spu.PurchaseLimitTypeEnum;
import cn.iocoder.yudao.module.promotion.api.giftvoucher.GiftVoucherApi;
import cn.iocoder.yudao.module.promotion.api.giftvoucher.dto.GiftVoucherRespDTO;
import cn.iocoder.yudao.module.system.api.social.SocialClientApi;
@@ -78,12 +78,9 @@ import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import javax.validation.constraints.NotNull;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
@@ -152,47 +149,73 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
// =================== Order ===================
public List<TradeOrderItemDO> findUserSuccessOrderItem(Long payUserId, List<Long> skuIdList, ProductSkuPurchaseBizTypeEnum status) {
List<Integer> statusList = new ArrayList<>();
statusList.add(TradeOrderStatusEnum.UNPAID.getStatus());
statusList.add(TradeOrderStatusEnum.UNDELIVERED.getStatus());
statusList.add(TradeOrderStatusEnum.DELIVERED.getStatus());
statusList.add(TradeOrderStatusEnum.COMPLETED.getStatus());
// 查询用户订单
LambdaQueryWrapperX<TradeOrderDO> orderQuery = new LambdaQueryWrapperX<TradeOrderDO>().eq(TradeOrderDO::getUserId, payUserId).in(TradeOrderDO::getStatus, statusList);
// 限购一天一次
if (ObjectUtil.equals(status, ProductSkuPurchaseBizTypeEnum.ONCE_A_DAY)) {
orderQuery.between(TradeOrderDO::getCreateTime, LocalDate.now(), LocalDate.now().plusDays(1));
}
List<TradeOrderDO> orderList = tradeOrderMapper.selectList(orderQuery);
if (ObjectUtil.isEmpty(orderList)) return null;
List<Long> orderIds = orderList.stream().map(TradeOrderDO::getId).collect(Collectors.toList());
// 查询订单项
List<TradeOrderItemDO> orderItemList = tradeOrderItemMapper.selectList(new LambdaQueryWrapperX<TradeOrderItemDO>()
.eq(TradeOrderItemDO::getUserId, payUserId)
.in(TradeOrderItemDO::getOrderId, orderIds)
);
if (ObjectUtil.isEmpty(orderItemList)) return null;
orderItemList = orderItemList.stream().filter(v -> skuIdList.contains(v.getSkuId())).collect(Collectors.toList());
return orderItemList;
}
/**
* 判断sku是否限购
* 结算阶段限购预校验(按 SPU 限购规则)
*/
@Override
public void isSkuPurchaseLimit(Long payUserId, List<Long> skuIdList) {
List<ProductSkuRespDTO> skuList = productSkuApi.getSkuList(skuIdList);
// 检查每天限购一次
ProductSkuPurchaseBizTypeEnum onceADayStatus = ProductSkuPurchaseBizTypeEnum.ONCE_A_DAY;
List<ProductSkuRespDTO> onceADay = skuList.stream().filter((v) -> ObjectUtil.equals(v.getPurchaseBizType(), onceADayStatus.getStatus())).collect(Collectors.toList());
if (ObjectUtil.isNotEmpty(onceADay)) {
List<Long> targetIdList = onceADay.stream().map(ProductSkuRespDTO::getId).collect(Collectors.toList());
List<TradeOrderItemDO> targetSkuList = findUserSuccessOrderItem(payUserId, targetIdList, onceADayStatus);
if (ObjectUtil.isNotEmpty(targetSkuList)) {
String spuName = targetSkuList.stream().map(TradeOrderItemDO::getSpuName).collect(Collectors.joining());
throw exception(ORDER_RECEIVE_FAIL_STATUS_PURCHASE, "【" + spuName + "】", onceADayStatus.getName());
if (CollUtil.isEmpty(skuList)) {
return;
}
// 本次请求每个 SPU 的购买数量(按 skuList 聚合;结算页通常每条 sku 一项)
Map<Long, Integer> currentPurchaseBySpu = new HashMap<>();
for (ProductSkuRespDTO sku : skuList) {
if (sku == null || sku.getSpuId() == null) {
continue;
}
currentPurchaseBySpu.merge(sku.getSpuId(), 1, Integer::sum);
}
if (currentPurchaseBySpu.isEmpty()) {
return;
}
List<ProductSpuRespDTO> spuList = productSpuApi.getSpuList(new ArrayList<>(currentPurchaseBySpu.keySet()));
if (CollUtil.isEmpty(spuList)) {
return;
}
for (ProductSpuRespDTO spu : spuList) {
if (spu == null || spu.getId() == null) {
continue;
}
Integer limitType = spu.getPurchaseLimitType();
Integer limitCount = spu.getPurchaseLimitCount();
if (limitType == null || Objects.equals(limitType, PurchaseLimitTypeEnum.NONE.getType())
|| limitCount == null || limitCount <= 0) {
continue; // 不限购
}
PurchaseLimitTypeEnum limitTypeEnum = PurchaseLimitTypeEnum.valueOf(limitType);
if (limitTypeEnum == null) {
continue;
}
LocalDateTime startTime = getStartTimeByLimitType(limitTypeEnum);
if (startTime == null) {
startTime = LocalDateTime.of(2000, 1, 1, 0, 0);
}
int historyPurchaseCount = tradeOrderItemMapper.selectPurchaseCountByUserAndSpu(payUserId, spu.getId(), startTime);
int currentPurchaseCount = currentPurchaseBySpu.getOrDefault(spu.getId(), 0);
if (historyPurchaseCount + currentPurchaseCount > limitCount) {
throw exception(ORDER_CREATE_PURCHASE_LIMIT_EXCEED, spu.getName(), limitTypeEnum.getName(), limitCount);
}
}
}
private LocalDateTime getStartTimeByLimitType(PurchaseLimitTypeEnum limitType) {
LocalDateTime now = LocalDateTime.now();
switch (limitType) {
case DAILY:
return now.toLocalDate().atStartOfDay();
case WEEKLY:
return now.with(TemporalAdjusters.previousOrSame(java.time.DayOfWeek.MONDAY))
.toLocalDate().atStartOfDay();
case LIFETIME:
return null;
default:
return null;
}
}
@@ -22,7 +22,7 @@ public enum DispenseResultStatusEnum {
CHANNEL_ERROR(6, "通道号错误"),
CHANNEL_TYPE_ERROR(7, "通道类型错误"),
/** 系统/业务异常(如网络异常、参数错误等) */
EXCEPTION(500, "出货异常"),
EXCEPTION(99, "出货异常"),
;
private final int value;
@@ -107,7 +107,7 @@ public class TradeDeviceOrderHandler implements TradeOrderHandler {
} catch (Throwable ex) {
// 兜底保护:这里不再向上抛异常,仅记录日志,避免影响支付回调流程
log.error("订单--{}:[设备出货处理异常]:原因: {}", order.getNo(), ex.getMessage(), ex);
deviceLogSaveReqVO.setDeviceStatus(500);
deviceLogSaveReqVO.setDeviceStatus(99);
deviceLogSaveReqVO.setContent("[出货异常]原因:" + ex.getMessage());
deviceLogService.createDeviceLog(deviceLogSaveReqVO);
}
@@ -137,7 +137,7 @@ public class TradeDeviceOrderHandler implements TradeOrderHandler {
List<ProductSpuRespDTO> spuList = productSpuApi.getSpuList(spuIds);
if (CollUtil.isEmpty(spuList)) {
log.error("订单:{}, 提货柜订单spu列表为空", order.getNo());
deviceLogSaveReqVO.setDeviceStatus(500);
deviceLogSaveReqVO.setDeviceStatus(99);
deviceLogSaveReqVO.setContent("[出货异常]原因:提货柜订单spu列表为空");
deviceLogService.createDeviceLog(deviceLogSaveReqVO);
return;
@@ -148,6 +148,8 @@ public class TradeDeviceOrderHandler implements TradeOrderHandler {
log.error("订单:{}, 中包含非提货柜商品,跳过设备出货处理", order.getNo());
return;
}
Map<Long, String> spuNameMap = spuList.stream()
.collect(Collectors.toMap(ProductSpuRespDTO::getId, ProductSpuRespDTO::getName, (a, b) -> a));
String deviceId = findUniqueDeviceId(order, spuList, deviceLogSaveReqVO);
if (deviceId == null) {
@@ -160,13 +162,13 @@ public class TradeDeviceOrderHandler implements TradeOrderHandler {
if (CollUtil.isEmpty(skuListBySpu)) {
log.warn("订单:{} 商品下无货道(SKU),跳过设备出货处理", order.getNo());
deviceLogSaveReqVO.setDeviceId(deviceId);
deviceLogSaveReqVO.setDeviceStatus(500);
deviceLogSaveReqVO.setDeviceStatus(99);
deviceLogSaveReqVO.setContent("[出货异常]原因:商品下无货道(SKU)");
deviceLogService.createDeviceLog(deviceLogSaveReqVO);
return;
}
String cabinetType = findUniqueCabinetType(order, skuListBySpu, deviceId, deviceLogSaveReqVO);
String cabinetType = findUniqueCabinetType(order, skuListBySpu, spuNameMap, deviceId, deviceLogSaveReqVO);
if (cabinetType == null) {
// 已在方法内部记录日志
return;
@@ -176,7 +178,7 @@ public class TradeDeviceOrderHandler implements TradeOrderHandler {
DispenseRequestBo request = buildDispenseRequest(order, orderItems, deviceId, cabinetType);
if (request == null) {
deviceLogSaveReqVO.setDeviceId(deviceId);
deviceLogSaveReqVO.setDeviceStatus(500);
deviceLogSaveReqVO.setDeviceStatus(99);
deviceLogSaveReqVO.setContent("[出货异常]原因:存在商品无可用货道(有库存且通道类型匹配)");
deviceLogService.createDeviceLog(deviceLogSaveReqVO);
return;
@@ -213,7 +215,7 @@ public class TradeDeviceOrderHandler implements TradeOrderHandler {
.count() == 1;
if (!isSingleDevice) {
log.error("订单:{}, 明细中包含多个设备的商品", order.getNo());
deviceLogSaveReqVO.setDeviceStatus(500);
deviceLogSaveReqVO.setDeviceStatus(99);
deviceLogSaveReqVO.setContent("[出货异常]原因:订单明细中包含多台贩卖机商品");
deviceLogService.createDeviceLog(deviceLogSaveReqVO);
return null;
@@ -223,7 +225,7 @@ public class TradeDeviceOrderHandler implements TradeOrderHandler {
if (deviceId == null) {
// 设备编号为空,无法出货
log.error("订单:{}, 商品的设备编号为空", order.getNo());
deviceLogSaveReqVO.setDeviceStatus(500);
deviceLogSaveReqVO.setDeviceStatus(99);
deviceLogSaveReqVO.setContent("[出货异常]原因:商品的设备编号为空");
deviceLogService.createDeviceLog(deviceLogSaveReqVO);
return null;
@@ -236,6 +238,7 @@ public class TradeDeviceOrderHandler implements TradeOrderHandler {
*/
private String findUniqueCabinetType(TradeOrderDO order,
List<ProductSkuRespDTO> skuList,
Map<Long, String> spuNameMap,
String deviceId,
DeviceLogSaveReqVO deviceLogSaveReqVO) {
boolean isSingleCabinetType = skuList.stream()
@@ -243,15 +246,28 @@ public class TradeDeviceOrderHandler implements TradeOrderHandler {
.distinct()
.count() == 1;
if (!isSingleCabinetType) {
log.error("订单:{}, 明细中包含多个通道类型", order.getNo());
deviceLogSaveReqVO.setDeviceId(deviceId);
deviceLogSaveReqVO.setDeviceStatus(500);
deviceLogSaveReqVO.setContent("[出货异常]原因:订单明细中包含多个通道类型");
deviceLogService.createDeviceLog(deviceLogSaveReqVO);
return null;
// 临时放开校验:不再因“多个通道类型”中断出货流程,仅记录告警日志便于排查
log.warn("订单:{}, 明细中包含多个通道类型,已跳过该校验并继续出货", order.getNo());
Map<String, List<ProductSkuRespDTO>> skuByCabinetType = skuList.stream()
.collect(Collectors.groupingBy(sku -> StrUtil.blankToDefault(sku.getCabinetType(), "<null>")));
skuByCabinetType.forEach((type, skus) -> {
String details = skus.stream()
.map(sku -> String.format("spuId=%s,spuName=%s,skuId=%s,cabinetType=%s,cabinetChannel=%s",
sku.getSpuId(),
spuNameMap.getOrDefault(sku.getSpuId(), "<unknown>"),
sku.getId(),
sku.getCabinetType(),
sku.getCabinetChannel()))
.collect(Collectors.joining(" | "));
log.warn("订单:{}, 通道类型分组[{}] -> {}", order.getNo(), type, details);
});
}
return skuList.get(0).getCabinetType();
return skuList.stream()
.map(ProductSkuRespDTO::getCabinetType)
.filter(StrUtil::isNotBlank)
.findFirst()
.orElse(skuList.get(0).getCabinetType());
}
/**
@@ -334,7 +350,7 @@ public class TradeDeviceOrderHandler implements TradeOrderHandler {
if (body == null) {
log.error("订单--{}:[出货失败]:响应体为空", order.getNo());
deviceLogSaveReqVO.setDeviceId(request.getDeviceId());
deviceLogSaveReqVO.setDeviceStatus(500);
deviceLogSaveReqVO.setDeviceStatus(99);
deviceLogSaveReqVO.setContent("[出货失败]原因:响应为空");
deviceLogService.createDeviceLog(deviceLogSaveReqVO);
return;
@@ -357,7 +373,7 @@ public class TradeDeviceOrderHandler implements TradeOrderHandler {
// HTTP 请求异常
log.error("订单--{}:[出货异常]:原因: {}", order.getNo(), e.getMessage(), e);
deviceLogSaveReqVO.setDeviceId(request.getDeviceId());
deviceLogSaveReqVO.setDeviceStatus(500);
deviceLogSaveReqVO.setDeviceStatus(99);
deviceLogSaveReqVO.setContent("[出货异常]原因:" + e.getMessage());
deviceLogService.createDeviceLog(deviceLogSaveReqVO);
}
@@ -117,7 +117,7 @@ public class TradeGiftVoucherOrderHandler implements TradeOrderHandler {
if (deviceId == null){
//imei为空
log.error("订单:{},商品的设备编号为空",order.getNo());
deviceLogSaveReqVO.setDeviceStatus(500);
deviceLogSaveReqVO.setDeviceStatus(99);
deviceLogSaveReqVO.setContent("[出货异常]原因:商品的设备编号为空");
deviceLogService.createDeviceLog(deviceLogSaveReqVO);
return;
@@ -203,7 +203,7 @@ public class TradeGiftVoucherOrderHandler implements TradeOrderHandler {
System.err.println("请求异常: " + e.getMessage());
log.error("订单--{}:[出货异常]:原因: {}",order.getNo(), e.getMessage());
deviceLogSaveReqVO.setDeviceId(deviceId);
deviceLogSaveReqVO.setDeviceStatus(500);
deviceLogSaveReqVO.setDeviceStatus(99);
deviceLogSaveReqVO.setContent("[出货异常]原因:"+e.getMessage());
deviceLogService.createDeviceLog(deviceLogSaveReqVO);
}
@@ -211,14 +211,14 @@ public class TradeGiftVoucherOrderHandler implements TradeOrderHandler {
System.out.println("订单明细中包含多个通道类型");
log.error("订单:{},明细中包含多个通道类型",order.getNo());
deviceLogSaveReqVO.setDeviceId(deviceId);
deviceLogSaveReqVO.setDeviceStatus(500);
deviceLogSaveReqVO.setDeviceStatus(99);
deviceLogSaveReqVO.setContent("[出货异常]原因:订单明细中包含多个通道类型");
deviceLogService.createDeviceLog(deviceLogSaveReqVO);
}
} else {
System.out.println("订单明细中包含多个商品创建人");
log.error("订单:{},明细中包含多个商品创建人",order.getNo());
deviceLogSaveReqVO.setDeviceStatus(500);
deviceLogSaveReqVO.setDeviceStatus(99);
deviceLogSaveReqVO.setContent("[出货异常]原因:订单明细中包含多台贩卖机商品");
deviceLogService.createDeviceLog(deviceLogSaveReqVO);
}
@@ -226,7 +226,7 @@ public class TradeGiftVoucherOrderHandler implements TradeOrderHandler {
}else {
System.out.println("提货柜订单spu列表为空");
log.error("订单:{},提货柜订单spu列表为空",order.getNo());
deviceLogSaveReqVO.setDeviceStatus(500);
deviceLogSaveReqVO.setDeviceStatus(99);
deviceLogSaveReqVO.setContent("[出货异常]原因:提货柜订单spu列表为空");
deviceLogService.createDeviceLog(deviceLogSaveReqVO);
}