trade:增加自动收货的 job

This commit is contained in:
YunaiV 2023-09-26 19:27:37 +08:00
parent 9e99b04375
commit a8c78f3097
9 changed files with 233 additions and 146 deletions

View File

@ -15,9 +15,10 @@ public enum TradeOrderOperateTypeEnum {
MEMBER_CREATE(1, "用户下单"), MEMBER_CREATE(1, "用户下单"),
MEMBER_RECEIVE(30, "用户已收货"), MEMBER_RECEIVE(30, "用户已收货"),
MEMBER_COMMENT(31, "用户评价"), SYSTEM_RECEIVE(31, "到期未收货,系统自动确认收货"),
MEMBER_CANCEL(40, "手动取消订单"), MEMBER_COMMENT(33, "用户评价"),
SYSTEM_CANCEL(41, "系统取消订单"), MEMBER_CANCEL(40, "取消订单"),
SYSTEM_CANCEL(41, "到期未支付,系统自动取消订单"),
// 42 预留管理员取消订单 // 42 预留管理员取消订单
MEMBER_DELETE(43, "删除订单"), MEMBER_DELETE(43, "删除订单"),
; ;

View File

@ -110,7 +110,7 @@ public interface TradeOrderConvert {
createReqDTO.setSubject(subject); createReqDTO.setSubject(subject);
createReqDTO.setBody(subject); // TODO 芋艿临时写死 createReqDTO.setBody(subject); // TODO 芋艿临时写死
// 订单相关字段 // 订单相关字段
createReqDTO.setPrice(order.getPayPrice()).setExpireTime(addTime(orderProperties.getExpireTime())); createReqDTO.setPrice(order.getPayPrice()).setExpireTime(addTime(orderProperties.getPayExpireTime()));
return createReqDTO; return createReqDTO;
} }
@ -180,7 +180,7 @@ public interface TradeOrderConvert {
TradeOrderProperties tradeOrderProperties, TradeOrderProperties tradeOrderProperties,
DeliveryExpressDO express) { DeliveryExpressDO express) {
AppTradeOrderDetailRespVO orderVO = convert3(order, orderItems); AppTradeOrderDetailRespVO orderVO = convert3(order, orderItems);
orderVO.setPayExpireTime(addTime(tradeOrderProperties.getExpireTime())); orderVO.setPayExpireTime(addTime(tradeOrderProperties.getPayExpireTime()));
if (StrUtil.isNotEmpty(order.getPayChannelCode())) { if (StrUtil.isNotEmpty(order.getPayChannelCode())) {
orderVO.setPayChannelName(DictFrameworkUtils.getDictDataLabel(DictTypeConstants.CHANNEL_CODE, order.getPayChannelCode())); orderVO.setPayChannelName(DictFrameworkUtils.getDictDataLabel(DictTypeConstants.CHANNEL_CODE, order.getPayChannelCode()));
} }

View File

@ -61,10 +61,16 @@ public interface TradeOrderMapper extends BaseMapperX<TradeOrderDO> {
.eq(TradeOrderDO::getUserId, loginUserId)); .eq(TradeOrderDO::getUserId, loginUserId));
} }
default List<TradeOrderDO> selectListByStatusAndCreateTimeLt(Integer status, LocalDateTime expireTime) { default List<TradeOrderDO> selectListByStatusAndCreateTimeLt(Integer status, LocalDateTime createTime) {
return selectList(new LambdaUpdateWrapper<TradeOrderDO>() return selectList(new LambdaUpdateWrapper<TradeOrderDO>()
.eq(TradeOrderDO::getStatus, status) .eq(TradeOrderDO::getStatus, status)
.lt(TradeOrderDO::getCreateTime, expireTime)); .lt(TradeOrderDO::getCreateTime, createTime));
}
default List<TradeOrderDO> selectListByStatusAndDeliveryTimeLt(Integer status, LocalDateTime deliveryTime) {
return selectList(new LambdaUpdateWrapper<TradeOrderDO>()
.eq(TradeOrderDO::getStatus, status)
.lt(TradeOrderDO::getDeliveryTime, deliveryTime));
} }
} }

View File

@ -28,6 +28,12 @@ public class TradeOrderProperties {
* 支付超时时间 * 支付超时时间
*/ */
@NotNull(message = "支付超时时间不能为空") @NotNull(message = "支付超时时间不能为空")
private Duration expireTime; private Duration payExpireTime;
/**
* 收货超时时间
*/
@NotNull(message = "收货超时时间不能为空")
private Duration receiveExpireTime;
} }

View File

@ -0,0 +1,28 @@
package cn.iocoder.yudao.module.trade.job.order;
import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
import cn.iocoder.yudao.framework.tenant.core.job.TenantJob;
import cn.iocoder.yudao.module.trade.service.order.TradeOrderUpdateService;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* 交易订单的自动收货 Job
*
* @author 芋道源码
*/
@Component
@TenantJob
public class TradeOrderAutoReceiveJob implements JobHandler {
@Resource
private TradeOrderUpdateService tradeOrderUpdateService;
@Override
public String execute(String param) {
int count = tradeOrderUpdateService.autoReceiveOrder();
return String.format("自动收货 %s 个", count);
}
}

View File

@ -63,7 +63,14 @@ public interface TradeOrderUpdateService {
void receiveOrder(Long userId, Long id); void receiveOrder(Long userId, Long id);
/** /**
* 会员取消订单 * 系统自动收货交易订单
*
* @return 收货数量
*/
int autoReceiveOrder();
/**
* 会员取消交易订单
* *
* @param userId 用户编号 * @param userId 用户编号
* @param id 订单编号 * @param id 订单编号

View File

@ -492,6 +492,50 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
// 校验并获得交易订单可收货 // 校验并获得交易订单可收货
TradeOrderDO order = validateOrderReceivable(userId, id); TradeOrderDO order = validateOrderReceivable(userId, id);
// 收货订单
receiveOrder0(order);
}
@Override
public int autoReceiveOrder() {
// 1. 查询过期的待支付订单
LocalDateTime expireTime = addTime(tradeOrderProperties.getReceiveExpireTime());
List<TradeOrderDO> orders = tradeOrderMapper.selectListByStatusAndDeliveryTimeLt(
TradeOrderStatusEnum.DELIVERED.getStatus(), expireTime);
if (CollUtil.isEmpty(orders)) {
return 0;
}
// 2. 遍历执行逐个取消
int count = 0;
for (TradeOrderDO order : orders) {
try {
getSelf().autoReceiveOrder(order);
count ++;
} catch (Throwable e) {
log.error("[autoReceiveOrder][order({}) 自动收货订单异常]", order.getId(), e);
}
}
return count;
}
/**
* 自动收货单个订单
*
* @param order 订单
*/
@Transactional(rollbackFor = Exception.class)
@TradeOrderLog(operateType = TradeOrderOperateTypeEnum.SYSTEM_RECEIVE)
public void autoReceiveOrder(TradeOrderDO order) {
receiveOrder0(order);
}
/**
* 收货订单的核心实现
*
* @param order 订单
*/
private void receiveOrder0(TradeOrderDO order) {
// 更新 TradeOrderDO 状态为已完成 // 更新 TradeOrderDO 状态为已完成
int updateCount = tradeOrderMapper.updateByIdAndStatus(order.getId(), order.getStatus(), int updateCount = tradeOrderMapper.updateByIdAndStatus(order.getId(), order.getStatus(),
new TradeOrderDO().setStatus(TradeOrderStatusEnum.COMPLETED.getStatus()).setReceiveTime(LocalDateTime.now())); new TradeOrderDO().setStatus(TradeOrderStatusEnum.COMPLETED.getStatus()).setReceiveTime(LocalDateTime.now()));
@ -499,16 +543,139 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
throw exception(ORDER_RECEIVE_FAIL_STATUS_NOT_DELIVERED); throw exception(ORDER_RECEIVE_FAIL_STATUS_NOT_DELIVERED);
} }
// TODO 芋艿lili 发送订单变化的消息
// TODO 芋艿lili 发送商品被购买完成的数据
// TODO 芋艿销售佣金的记录
// 插入订单日志 // 插入订单日志
TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), TradeOrderStatusEnum.COMPLETED.getStatus()); TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), TradeOrderStatusEnum.COMPLETED.getStatus());
} }
/**
* 校验交易订单满足可售货的条件
*
* 1. 交易订单待收货
*
* @param userId 用户编号
* @param id 交易订单编号
* @return 交易订单
*/
private TradeOrderDO validateOrderReceivable(Long userId, Long id) {
// 校验订单是否存在
TradeOrderDO order = tradeOrderMapper.selectByIdAndUserId(id, userId);
if (order == null) {
throw exception(ORDER_NOT_FOUND);
}
// 校验订单是否是待收货状态
if (!TradeOrderStatusEnum.isDelivered(order.getStatus())) {
throw exception(ORDER_RECEIVE_FAIL_STATUS_NOT_DELIVERED);
}
return order;
}
@Override
@Transactional(rollbackFor = Exception.class)
@TradeOrderLog(operateType = TradeOrderOperateTypeEnum.MEMBER_CANCEL)
public void cancelOrder(Long userId, Long id) {
// 1.1 校验存在
TradeOrderDO order = tradeOrderMapper.selectOrderByIdAndUserId(id, userId);
if (order == null) {
throw exception(ORDER_NOT_FOUND);
}
// 1.2 校验状态
if (ObjectUtil.notEqual(order.getStatus(), TradeOrderStatusEnum.UNPAID.getStatus())) {
throw exception(ORDER_CANCEL_FAIL_STATUS_NOT_UNPAID);
}
// 2. 取消订单
cancelOrder0(order, TradeOrderCancelTypeEnum.MEMBER_CANCEL);
}
@Override
public int autoCancelOrder() {
// 1. 查询过期的待支付订单
LocalDateTime expireTime = addTime(tradeOrderProperties.getPayExpireTime());
List<TradeOrderDO> orders = tradeOrderMapper.selectListByStatusAndCreateTimeLt(
TradeOrderStatusEnum.UNPAID.getStatus(), expireTime);
if (CollUtil.isEmpty(orders)) {
return 0;
}
// 2. 遍历执行逐个取消
int count = 0;
for (TradeOrderDO order : orders) {
try {
getSelf().autoCancelOrder(order);
count ++;
} catch (Throwable e) {
log.error("[autoCancelOrder][order({}) 过期订单异常]", order.getId(), e);
}
}
return count;
}
/**
* 自动取消单个订单
*
* @param order 订单
*/
@Transactional(rollbackFor = Exception.class)
@TradeOrderLog(operateType = TradeOrderOperateTypeEnum.SYSTEM_CANCEL)
public void autoCancelOrder(TradeOrderDO order) {
cancelOrder0(order, TradeOrderCancelTypeEnum.PAY_TIMEOUT);
}
/**
* 取消订单的核心实现
*
* @param order 订单
* @param cancelType 取消类型
*/
private void cancelOrder0(TradeOrderDO order, TradeOrderCancelTypeEnum cancelType) {
Long id = order.getId();
// 1. 更新 TradeOrderDO 状态为已取消
int updateCount = tradeOrderMapper.updateByIdAndStatus(id, order.getStatus(),
new TradeOrderDO().setStatus(TradeOrderStatusEnum.CANCELED.getStatus())
.setCancelType(cancelType.getType()).setCancelTime(LocalDateTime.now()));
if (updateCount == 0) {
throw exception(ORDER_CANCEL_FAIL_STATUS_NOT_UNPAID);
}
// 2. TODO 活动相关库存回滚需要活动 id活动 id 怎么获取app 端能否传过来回复从订单里拿呀
tradeOrderHandlers.forEach(handler -> handler.rollback());
// 3. 回滚库存
List<TradeOrderItemDO> orderItems = tradeOrderItemMapper.selectListByOrderId(id);
productSkuApi.updateSkuStock(TradeOrderConvert.INSTANCE.convert(orderItems));
// 4. 回滚优惠券
if (order.getCouponId() != null && order.getCouponId() > 0) {
couponApi.returnUsedCoupon(order.getCouponId());
}
// 5. 回滚积分抵扣的
addUserPoint(order.getUserId(), order.getUsePoint(), MemberPointBizTypeEnum.ORDER_CANCEL, order.getId());
// 6. 增加订单日志
TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), TradeOrderStatusEnum.CANCELED.getStatus());
}
@Override
@Transactional(rollbackFor = Exception.class)
@TradeOrderLog(operateType = TradeOrderOperateTypeEnum.MEMBER_DELETE)
public void deleteOrder(Long userId, Long id) {
// 1.1 校验存在
TradeOrderDO order = tradeOrderMapper.selectOrderByIdAndUserId(id, userId);
if (order == null) {
throw exception(ORDER_NOT_FOUND);
}
// 1.2 校验状态
if (ObjectUtil.notEqual(order.getStatus(), TradeOrderStatusEnum.CANCELED.getStatus())) {
throw exception(ORDER_DELETE_FAIL_STATUS_NOT_CANCEL);
}
// 2. 删除订单
tradeOrderMapper.deleteById(id);
// 3. 记录日志
TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), order.getStatus());
}
@Override @Override
public void updateOrderRemark(TradeOrderRemarkReqVO reqVO) { public void updateOrderRemark(TradeOrderRemarkReqVO reqVO) {
// 校验并获得交易订单 // 校验并获得交易订单
@ -604,28 +771,6 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
tradeOrderMapper.updateById(update); tradeOrderMapper.updateById(update);
} }
/**
* 校验交易订单满足可售货的条件
*
* 1. 交易订单待收货
*
* @param userId 用户编号
* @param id 交易订单编号
* @return 交易订单
*/
private TradeOrderDO validateOrderReceivable(Long userId, Long id) {
// 校验订单是否存在
TradeOrderDO order = tradeOrderMapper.selectByIdAndUserId(id, userId);
if (order == null) {
throw exception(ORDER_NOT_FOUND);
}
// 校验订单是否是待收货状态
if (!TradeOrderStatusEnum.isDelivered(order.getStatus())) {
throw exception(ORDER_RECEIVE_FAIL_STATUS_NOT_DELIVERED);
}
return order;
}
// =================== Order Item =================== // =================== Order Item ===================
@Override @Override
@ -723,113 +868,6 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
return comment; return comment;
} }
@Override
@Transactional(rollbackFor = Exception.class)
@TradeOrderLog(operateType = TradeOrderOperateTypeEnum.MEMBER_CANCEL)
public void cancelOrder(Long userId, Long id) {
// 1.1 校验存在
TradeOrderDO order = tradeOrderMapper.selectOrderByIdAndUserId(id, userId);
if (order == null) {
throw exception(ORDER_NOT_FOUND);
}
// 1.2 校验状态
if (ObjectUtil.notEqual(order.getStatus(), TradeOrderStatusEnum.UNPAID.getStatus())) {
throw exception(ORDER_CANCEL_FAIL_STATUS_NOT_UNPAID);
}
// 2. 取消订单
cancelOrder0(order, TradeOrderCancelTypeEnum.MEMBER_CANCEL);
}
@Override
public int autoCancelOrder() {
// 1. 查询过期的待支付订单
LocalDateTime expireTime = addTime(tradeOrderProperties.getExpireTime());
List<TradeOrderDO> orders = tradeOrderMapper.selectListByStatusAndCreateTimeLt(
TradeOrderStatusEnum.UNPAID.getStatus(), expireTime);
if (CollUtil.isEmpty(orders)) {
return 0;
}
// 2. 遍历执行逐个取消
int count = 0;
for (TradeOrderDO order : orders) {
try {
getSelf().autoCancelOrder(order);
count ++;
} catch (Throwable e) {
log.error("[autoCancelOrder][order({}) 过期订单异常]", order.getId(), e);
}
}
return count;
}
/**
* 自动取消单个订单
*
* @param order 订单
*/
@Transactional(rollbackFor = Exception.class)
@TradeOrderLog(operateType = TradeOrderOperateTypeEnum.SYSTEM_CANCEL)
public void autoCancelOrder(TradeOrderDO order) {
cancelOrder0(order, TradeOrderCancelTypeEnum.PAY_TIMEOUT);
}
/**
* 取消订单的核心实现
*
* @param order 订单
* @param cancelType 取消类型
*/
private void cancelOrder0(TradeOrderDO order, TradeOrderCancelTypeEnum cancelType) {
Long id = order.getId();
// 1. 更新 TradeOrderDO 状态为已取消
int updateCount = tradeOrderMapper.updateByIdAndStatus(id, order.getStatus(),
new TradeOrderDO().setStatus(TradeOrderStatusEnum.CANCELED.getStatus())
.setCancelType(cancelType.getType()).setCancelTime(LocalDateTime.now()));
if (updateCount == 0) {
throw exception(ORDER_CANCEL_FAIL_STATUS_NOT_UNPAID);
}
// 2. TODO 活动相关库存回滚需要活动 id活动 id 怎么获取app 端能否传过来回复从订单里拿呀
tradeOrderHandlers.forEach(handler -> handler.rollback());
// 3. 回滚库存
List<TradeOrderItemDO> orderItems = tradeOrderItemMapper.selectListByOrderId(id);
productSkuApi.updateSkuStock(TradeOrderConvert.INSTANCE.convert(orderItems));
// 4. 回滚优惠券
if (order.getCouponId() != null && order.getCouponId() > 0) {
couponApi.returnUsedCoupon(order.getCouponId());
}
// 5. 回滚积分抵扣的
addUserPoint(order.getUserId(), order.getUsePoint(), MemberPointBizTypeEnum.ORDER_CANCEL, order.getId());
// 6. 增加订单日志
TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), TradeOrderStatusEnum.CANCELED.getStatus());
}
@Override
@Transactional(rollbackFor = Exception.class)
@TradeOrderLog(operateType = TradeOrderOperateTypeEnum.MEMBER_DELETE)
public void deleteOrder(Long userId, Long id) {
// 1.1 校验存在
TradeOrderDO order = tradeOrderMapper.selectOrderByIdAndUserId(id, userId);
if (order == null) {
throw exception(ORDER_NOT_FOUND);
}
// 1.2 校验状态
if (ObjectUtil.notEqual(order.getStatus(), TradeOrderStatusEnum.CANCELED.getStatus())) {
throw exception(ORDER_DELETE_FAIL_STATUS_NOT_CANCEL);
}
// 2. 删除订单
tradeOrderMapper.deleteById(id);
// 3. 记录日志
TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), order.getStatus());
}
/** /**
* 判断指定订单的所有订单项是不是都售后成功 * 判断指定订单的所有订单项是不是都售后成功
* *

View File

@ -87,7 +87,7 @@ public class TradeOrderUpdateServiceTest extends BaseDbUnitTest {
@BeforeEach @BeforeEach
public void setUp() { public void setUp() {
when(tradeOrderProperties.getAppId()).thenReturn(888L); when(tradeOrderProperties.getAppId()).thenReturn(888L);
when(tradeOrderProperties.getExpireTime()).thenReturn(Duration.ofDays(1)); when(tradeOrderProperties.getPayExpireTime()).thenReturn(Duration.ofDays(1));
} }
@Test @Test

View File

@ -203,7 +203,8 @@ yudao:
trade: trade:
order: order:
app-id: 1 # 商户编号 app-id: 1 # 商户编号
expire-time: 2h # 支付的过期时间 pay-expire-time: 2h # 支付的过期时间
receive-expire-time: 14d # 收货的过期时间
express: express:
client: kd_niao client: kd_niao
kd-niao: kd-niao: