Commit cd2d0b708910d49399599446f2ec5c399234df13

Authored by owen
2 parents 77f77635 cf41347c

Merge remote-tracking branch 'origin/feature/mall_product' into feature/mall_product

Showing 24 changed files with 323 additions and 188 deletions
yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/dto/ProductSpuRespDTO.java
@@ -111,17 +111,19 @@ public class ProductSpuRespDTO { @@ -111,17 +111,19 @@ public class ProductSpuRespDTO {
111 // ========== 物流相关字段 ========= 111 // ========== 物流相关字段 =========
112 112
113 /** 113 /**
114 - * 赠送积分  
115 - */  
116 - private Integer giveIntegral;  
117 -  
118 - /**  
119 * 物流配置模板编号 114 * 物流配置模板编号
120 * 115 *
121 * 对应 TradeDeliveryExpressTemplateDO 的 id 编号 116 * 对应 TradeDeliveryExpressTemplateDO 的 id 编号
122 */ 117 */
123 private Long deliveryTemplateId; 118 private Long deliveryTemplateId;
124 119
  120 + // ========== 营销相关字段 =========
  121 +
  122 + /**
  123 + * 赠送积分
  124 + */
  125 + private Integer giveIntegral;
  126 +
125 // ========== 统计相关字段 ========= 127 // ========== 统计相关字段 =========
126 128
127 /** 129 /**
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderOperateTypeEnum.java
@@ -14,10 +14,12 @@ import lombok.RequiredArgsConstructor; @@ -14,10 +14,12 @@ import lombok.RequiredArgsConstructor;
14 public enum TradeOrderOperateTypeEnum { 14 public enum TradeOrderOperateTypeEnum {
15 15
16 MEMBER_CREATE(1, "用户下单"), 16 MEMBER_CREATE(1, "用户下单"),
  17 + MEMBER_PAY(20, "用户付款成功"),
17 MEMBER_RECEIVE(30, "用户已收货"), 18 MEMBER_RECEIVE(30, "用户已收货"),
18 - MEMBER_COMMENT(31, "用户评价"),  
19 - MEMBER_CANCEL(40, "手动取消订单"),  
20 - SYSTEM_CANCEL(41, "系统取消订单"), 19 + SYSTEM_RECEIVE(31, "到期未收货,系统自动确认收货"),
  20 + MEMBER_COMMENT(33, "用户评价"),
  21 + MEMBER_CANCEL(40, "取消订单"),
  22 + SYSTEM_CANCEL(41, "到期未支付,系统自动取消订单"),
21 // 42 预留:管理员取消订单 23 // 42 预留:管理员取消订单
22 MEMBER_DELETE(43, "删除订单"), 24 MEMBER_DELETE(43, "删除订单"),
23 ; 25 ;
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java
@@ -140,7 +140,7 @@ public class AppTradeOrderController { @@ -140,7 +140,7 @@ public class AppTradeOrderController {
140 @Operation(summary = "确认交易订单收货") 140 @Operation(summary = "确认交易订单收货")
141 @Parameter(name = "id", description = "交易订单编号") 141 @Parameter(name = "id", description = "交易订单编号")
142 public CommonResult<Boolean> receiveOrder(@RequestParam("id") Long id) { 142 public CommonResult<Boolean> receiveOrder(@RequestParam("id") Long id) {
143 - tradeOrderUpdateService.receiveOrder(getLoginUserId(), id); 143 + tradeOrderUpdateService.receiveOrderByMember(getLoginUserId(), id);
144 return success(true); 144 return success(true);
145 } 145 }
146 146
@@ -148,7 +148,7 @@ public class AppTradeOrderController { @@ -148,7 +148,7 @@ public class AppTradeOrderController {
148 @Operation(summary = "取消交易订单") 148 @Operation(summary = "取消交易订单")
149 @Parameter(name = "id", description = "交易订单编号") 149 @Parameter(name = "id", description = "交易订单编号")
150 public CommonResult<Boolean> cancelOrder(@RequestParam("id") Long id) { 150 public CommonResult<Boolean> cancelOrder(@RequestParam("id") Long id) {
151 - tradeOrderUpdateService.cancelOrder(getLoginUserId(), id); 151 + tradeOrderUpdateService.cancelOrderByMember(getLoginUserId(), id);
152 return success(true); 152 return success(true);
153 } 153 }
154 154
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java
@@ -110,7 +110,7 @@ public interface TradeOrderConvert { @@ -110,7 +110,7 @@ public interface TradeOrderConvert {
110 createReqDTO.setSubject(subject); 110 createReqDTO.setSubject(subject);
111 createReqDTO.setBody(subject); // TODO 芋艿:临时写死 111 createReqDTO.setBody(subject); // TODO 芋艿:临时写死
112 // 订单相关字段 112 // 订单相关字段
113 - createReqDTO.setPrice(order.getPayPrice()).setExpireTime(addTime(orderProperties.getExpireTime())); 113 + createReqDTO.setPrice(order.getPayPrice()).setExpireTime(addTime(orderProperties.getPayExpireTime()));
114 return createReqDTO; 114 return createReqDTO;
115 } 115 }
116 116
@@ -180,7 +180,7 @@ public interface TradeOrderConvert { @@ -180,7 +180,7 @@ public interface TradeOrderConvert {
180 TradeOrderProperties tradeOrderProperties, 180 TradeOrderProperties tradeOrderProperties,
181 DeliveryExpressDO express) { 181 DeliveryExpressDO express) {
182 AppTradeOrderDetailRespVO orderVO = convert3(order, orderItems); 182 AppTradeOrderDetailRespVO orderVO = convert3(order, orderItems);
183 - orderVO.setPayExpireTime(addTime(tradeOrderProperties.getExpireTime())); 183 + orderVO.setPayExpireTime(addTime(tradeOrderProperties.getPayExpireTime()));
184 if (StrUtil.isNotEmpty(order.getPayChannelCode())) { 184 if (StrUtil.isNotEmpty(order.getPayChannelCode())) {
185 orderVO.setPayChannelName(DictFrameworkUtils.getDictDataLabel(DictTypeConstants.CHANNEL_CODE, order.getPayChannelCode())); 185 orderVO.setPayChannelName(DictFrameworkUtils.getDictDataLabel(DictTypeConstants.CHANNEL_CODE, order.getPayChannelCode()));
186 } 186 }
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderItemDO.java
@@ -146,18 +146,20 @@ public class TradeOrderItemDO extends BaseDO { @@ -146,18 +146,20 @@ public class TradeOrderItemDO extends BaseDO {
146 private Integer pointPrice; 146 private Integer pointPrice;
147 /** 147 /**
148 * 使用的积分 148 * 使用的积分
  149 + *
  150 + * 目的:用于后续取消或者售后订单时,需要归还赠送
149 */ 151 */
150 private Integer usePoint; 152 private Integer usePoint;
151 /** 153 /**
152 * 赠送的积分 154 * 赠送的积分
  155 + *
  156 + * 目的:用于后续取消或者售后订单时,需要扣减赠送
153 */ 157 */
154 private Integer givePoint; 158 private Integer givePoint;
155 /** 159 /**
156 * VIP 减免金额,单位:分 160 * VIP 减免金额,单位:分
157 */ 161 */
158 private Integer vipPrice; 162 private Integer vipPrice;
159 - // TODO @芋艿:如果商品 vip 折扣时,到底是新增一个 vipPrice 记录优惠记录,还是 vipDiscountPrice,记录 vip 的优惠;还是直接使用 vipPrice;  
160 - // 目前 crmeb 的选择,单独一个 vipPrice 记录优惠价格;感觉不一定合理,可以在看看有赞的;  
161 163
162 // ========== 售后基本信息 ========== 164 // ========== 售后基本信息 ==========
163 165
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderMapper.java
@@ -61,10 +61,16 @@ public interface TradeOrderMapper extends BaseMapperX&lt;TradeOrderDO&gt; { @@ -61,10 +61,16 @@ public interface TradeOrderMapper extends BaseMapperX&lt;TradeOrderDO&gt; {
61 .eq(TradeOrderDO::getUserId, loginUserId)); 61 .eq(TradeOrderDO::getUserId, loginUserId));
62 } 62 }
63 63
64 - default List<TradeOrderDO> selectListByStatusAndCreateTimeLt(Integer status, LocalDateTime expireTime) { 64 + default List<TradeOrderDO> selectListByStatusAndCreateTimeLt(Integer status, LocalDateTime createTime) {
65 return selectList(new LambdaUpdateWrapper<TradeOrderDO>() 65 return selectList(new LambdaUpdateWrapper<TradeOrderDO>()
66 .eq(TradeOrderDO::getStatus, status) 66 .eq(TradeOrderDO::getStatus, status)
67 - .lt(TradeOrderDO::getCreateTime, expireTime)); 67 + .lt(TradeOrderDO::getCreateTime, createTime));
  68 + }
  69 +
  70 + default List<TradeOrderDO> selectListByStatusAndDeliveryTimeLt(Integer status, LocalDateTime deliveryTime) {
  71 + return selectList(new LambdaUpdateWrapper<TradeOrderDO>()
  72 + .eq(TradeOrderDO::getStatus, status)
  73 + .lt(TradeOrderDO::getDeliveryTime, deliveryTime));
68 } 74 }
69 75
70 } 76 }
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/order/config/TradeOrderProperties.java
@@ -28,6 +28,12 @@ public class TradeOrderProperties { @@ -28,6 +28,12 @@ public class TradeOrderProperties {
28 * 支付超时时间 28 * 支付超时时间
29 */ 29 */
30 @NotNull(message = "支付超时时间不能为空") 30 @NotNull(message = "支付超时时间不能为空")
31 - private Duration expireTime; 31 + private Duration payExpireTime;
  32 +
  33 + /**
  34 + * 收货超时时间
  35 + */
  36 + @NotNull(message = "收货超时时间不能为空")
  37 + private Duration receiveExpireTime;
32 38
33 } 39 }
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/order/core/annotations/TradeOrderLog.java
@@ -2,7 +2,10 @@ package cn.iocoder.yudao.module.trade.framework.order.core.annotations; @@ -2,7 +2,10 @@ package cn.iocoder.yudao.module.trade.framework.order.core.annotations;
2 2
3 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderOperateTypeEnum; 3 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderOperateTypeEnum;
4 4
5 -import java.lang.annotation.*; 5 +import java.lang.annotation.Documented;
  6 +import java.lang.annotation.Retention;
  7 +import java.lang.annotation.RetentionPolicy;
  8 +import java.lang.annotation.Target;
6 9
7 import static java.lang.annotation.ElementType.ANNOTATION_TYPE; 10 import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
8 import static java.lang.annotation.ElementType.METHOD; 11 import static java.lang.annotation.ElementType.METHOD;
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/order/core/aop/TradeOrderLogAspect.java
@@ -32,6 +32,16 @@ import static java.util.Collections.emptyMap; @@ -32,6 +32,16 @@ import static java.util.Collections.emptyMap;
32 public class TradeOrderLogAspect { 32 public class TradeOrderLogAspect {
33 33
34 /** 34 /**
  35 + * 用户编号
  36 + *
  37 + * 目前的使用场景:支付回调时,需要强制设置下用户编号
  38 + */
  39 + private static final ThreadLocal<Long> USER_ID = new ThreadLocal<>();
  40 + /**
  41 + * 用户类型
  42 + */
  43 + private static final ThreadLocal<Integer> USER_TYPE = new ThreadLocal<>();
  44 + /**
35 * 订单编号 45 * 订单编号
36 */ 46 */
37 private static final ThreadLocal<Long> ORDER_ID = new ThreadLocal<>(); 47 private static final ThreadLocal<Long> ORDER_ID = new ThreadLocal<>();
@@ -112,4 +122,9 @@ public class TradeOrderLogAspect { @@ -112,4 +122,9 @@ public class TradeOrderLogAspect {
112 EXTS.set(exts); 122 EXTS.set(exts);
113 } 123 }
114 124
  125 + public static void setUserInfo(Long userId, Integer userType) {
  126 + USER_ID.set(userId);
  127 + USER_TYPE.set(userType);
  128 + }
  129 +
115 } 130 }
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/order/core/utils/TradeOrderLogUtils.java
@@ -20,4 +20,8 @@ public class TradeOrderLogUtils { @@ -20,4 +20,8 @@ public class TradeOrderLogUtils {
20 TradeOrderLogAspect.setOrderInfo(id, beforeStatus, afterStatus, exts); 20 TradeOrderLogAspect.setOrderInfo(id, beforeStatus, afterStatus, exts);
21 } 21 }
22 22
  23 + public static void setUserInfo(Long userId, Integer userType) {
  24 + TradeOrderLogAspect.setUserInfo(userId, userType);
  25 + }
  26 +
23 } 27 }
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/job/order/TradeOrderAutoCancelJob.java
@@ -21,7 +21,7 @@ public class TradeOrderAutoCancelJob implements JobHandler { @@ -21,7 +21,7 @@ public class TradeOrderAutoCancelJob implements JobHandler {
21 21
22 @Override 22 @Override
23 public String execute(String param) { 23 public String execute(String param) {
24 - int count = tradeOrderUpdateService.autoCancelOrder(); 24 + int count = tradeOrderUpdateService.cancelOrderBySystem();
25 return String.format("过期订单 %s 个", count); 25 return String.format("过期订单 %s 个", count);
26 } 26 }
27 27
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/job/order/TradeOrderAutoReceiveJob.java 0 → 100644
  1 +package cn.iocoder.yudao.module.trade.job.order;
  2 +
  3 +import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
  4 +import cn.iocoder.yudao.framework.tenant.core.job.TenantJob;
  5 +import cn.iocoder.yudao.module.trade.service.order.TradeOrderUpdateService;
  6 +import org.springframework.stereotype.Component;
  7 +
  8 +import javax.annotation.Resource;
  9 +
  10 +/**
  11 + * 交易订单的自动收货 Job
  12 + *
  13 + * @author 芋道源码
  14 + */
  15 +@Component
  16 +@TenantJob
  17 +public class TradeOrderAutoReceiveJob implements JobHandler {
  18 +
  19 + @Resource
  20 + private TradeOrderUpdateService tradeOrderUpdateService;
  21 +
  22 + @Override
  23 + public String execute(String param) {
  24 + int count = tradeOrderUpdateService.receiveOrderBySystem();
  25 + return String.format("自动收货 %s 个", count);
  26 + }
  27 +
  28 +}
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateService.java
@@ -60,22 +60,29 @@ public interface TradeOrderUpdateService { @@ -60,22 +60,29 @@ public interface TradeOrderUpdateService {
60 * @param userId 用户编号 60 * @param userId 用户编号
61 * @param id 订单编号 61 * @param id 订单编号
62 */ 62 */
63 - void receiveOrder(Long userId, Long id); 63 + void receiveOrderByMember(Long userId, Long id);
64 64
65 /** 65 /**
66 - * 【会员】取消订单 66 + * 【系统】自动收货交易订单
  67 + *
  68 + * @return 收货数量
  69 + */
  70 + int receiveOrderBySystem();
  71 +
  72 + /**
  73 + * 【会员】取消交易订单
67 * 74 *
68 * @param userId 用户编号 75 * @param userId 用户编号
69 * @param id 订单编号 76 * @param id 订单编号
70 */ 77 */
71 - void cancelOrder(Long userId, Long id); 78 + void cancelOrderByMember(Long userId, Long id);
72 79
73 /** 80 /**
74 * 【系统】自动取消订单 81 * 【系统】自动取消订单
75 * 82 *
76 * @return 取消数量 83 * @return 取消数量
77 */ 84 */
78 - int autoCancelOrder(); 85 + int cancelOrderBySystem();
79 86
80 /** 87 /**
81 * 【会员】删除订单 88 * 【会员】删除订单
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java
@@ -8,6 +8,7 @@ import cn.hutool.core.util.StrUtil; @@ -8,6 +8,7 @@ import cn.hutool.core.util.StrUtil;
8 import cn.hutool.extra.spring.SpringUtil; 8 import cn.hutool.extra.spring.SpringUtil;
9 import cn.iocoder.yudao.framework.common.core.KeyValue; 9 import cn.iocoder.yudao.framework.common.core.KeyValue;
10 import cn.iocoder.yudao.framework.common.enums.TerminalEnum; 10 import cn.iocoder.yudao.framework.common.enums.TerminalEnum;
  11 +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
11 import cn.iocoder.yudao.framework.common.util.json.JsonUtils; 12 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
12 import cn.iocoder.yudao.module.member.api.address.AddressApi; 13 import cn.iocoder.yudao.module.member.api.address.AddressApi;
13 import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO; 14 import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO;
@@ -321,38 +322,39 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { @@ -321,38 +322,39 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
321 322
322 @Override 323 @Override
323 @Transactional(rollbackFor = Exception.class) 324 @Transactional(rollbackFor = Exception.class)
  325 + @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.MEMBER_PAY)
324 public void updateOrderPaid(Long id, Long payOrderId) { 326 public void updateOrderPaid(Long id, Long payOrderId) {
325 - // 校验并获得交易订单(可支付) 327 + // 1. 校验并获得交易订单(可支付)
326 KeyValue<TradeOrderDO, PayOrderRespDTO> orderResult = validateOrderPayable(id, payOrderId); 328 KeyValue<TradeOrderDO, PayOrderRespDTO> orderResult = validateOrderPayable(id, payOrderId);
327 TradeOrderDO order = orderResult.getKey(); 329 TradeOrderDO order = orderResult.getKey();
328 PayOrderRespDTO payOrder = orderResult.getValue(); 330 PayOrderRespDTO payOrder = orderResult.getValue();
329 331
330 - // 更新 TradeOrderDO 状态为已支付,等待发货 332 + // 2. 更新 TradeOrderDO 状态为已支付,等待发货
331 int updateCount = tradeOrderMapper.updateByIdAndStatus(id, order.getStatus(), 333 int updateCount = tradeOrderMapper.updateByIdAndStatus(id, order.getStatus(),
332 new TradeOrderDO().setStatus(TradeOrderStatusEnum.UNDELIVERED.getStatus()).setPayStatus(true) 334 new TradeOrderDO().setStatus(TradeOrderStatusEnum.UNDELIVERED.getStatus()).setPayStatus(true)
333 .setPayTime(LocalDateTime.now()).setPayChannelCode(payOrder.getChannelCode())); 335 .setPayTime(LocalDateTime.now()).setPayChannelCode(payOrder.getChannelCode()));
334 if (updateCount == 0) { 336 if (updateCount == 0) {
335 throw exception(ORDER_UPDATE_PAID_STATUS_NOT_UNPAID); 337 throw exception(ORDER_UPDATE_PAID_STATUS_NOT_UNPAID);
336 } 338 }
337 - // 校验活动 339 +
  340 + // 3. 校验活动
338 // 1、拼团活动 341 // 1、拼团活动
339 // TODO @puhui999:这块也抽象到 handler 里 342 // TODO @puhui999:这块也抽象到 handler 里
340 if (Objects.equals(TradeOrderTypeEnum.COMBINATION.getType(), order.getType())) { 343 if (Objects.equals(TradeOrderTypeEnum.COMBINATION.getType(), order.getType())) {
341 // 更新拼团状态 TODO puhui999:订单支付失败或订单支付过期删除这条拼团记录 344 // 更新拼团状态 TODO puhui999:订单支付失败或订单支付过期删除这条拼团记录
342 combinationRecordApi.updateRecordStatusToInProgress(order.getUserId(), order.getId(), LocalDateTime.now()); 345 combinationRecordApi.updateRecordStatusToInProgress(order.getUserId(), order.getId(), LocalDateTime.now());
343 } 346 }
344 - // TODO 芋艿:发送订单变化的消息  
345 -  
346 - // TODO 芋艿:发送站内信  
347 347
348 - // TODO 芋艿:OrderLog  
349 -  
350 - // 增加用户积分(赠送)  
351 - addUserPoint(order.getUserId(), order.getGivePoint(), MemberPointBizTypeEnum.ORDER_REWARD, order.getId());  
352 - // 增加用户经验 348 + // 4.1 增加用户积分(赠送)
  349 + addUserPoint(order.getUserId(), order.getGivePoint(), MemberPointBizTypeEnum.ORDER_GIVE, order.getId());
  350 + // 4.2 增加用户经验
353 getSelf().addUserExperienceAsync(order.getUserId(), order.getPayPrice(), order.getId()); 351 getSelf().addUserExperienceAsync(order.getUserId(), order.getPayPrice(), order.getId());
354 - // 增加用户佣金 352 + // 4.3 增加用户佣金
355 getSelf().addBrokerageAsync(order.getUserId(), order.getId()); 353 getSelf().addBrokerageAsync(order.getUserId(), order.getId());
  354 +
  355 + // 5. 记录订单日志
  356 + TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), TradeOrderStatusEnum.UNDELIVERED.getStatus());
  357 + TradeOrderLogUtils.setUserInfo(order.getUserId(), UserTypeEnum.MEMBER.getValue());
356 } 358 }
357 359
358 /** 360 /**
@@ -435,8 +437,6 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { @@ -435,8 +437,6 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
435 throw exception(ORDER_DELIVERY_FAIL_STATUS_NOT_UNDELIVERED); 437 throw exception(ORDER_DELIVERY_FAIL_STATUS_NOT_UNDELIVERED);
436 } 438 }
437 439
438 - // TODO 芋艿:发送订单变化的消息  
439 -  
440 // 发送站内信 440 // 发送站内信
441 tradeMessageService.sendMessageWhenDeliveryOrder(new TradeOrderMessageWhenDeliveryOrderReqBO().setOrderId(order.getId()) 441 tradeMessageService.sendMessageWhenDeliveryOrder(new TradeOrderMessageWhenDeliveryOrderReqBO().setOrderId(order.getId())
442 .setUserId(order.getUserId()).setMessage(null)); 442 .setUserId(order.getUserId()).setMessage(null));
@@ -488,10 +488,54 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { @@ -488,10 +488,54 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
488 @Override 488 @Override
489 @Transactional(rollbackFor = Exception.class) 489 @Transactional(rollbackFor = Exception.class)
490 @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.MEMBER_RECEIVE) 490 @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.MEMBER_RECEIVE)
491 - public void receiveOrder(Long userId, Long id) { 491 + public void receiveOrderByMember(Long userId, Long id) {
492 // 校验并获得交易订单(可收货) 492 // 校验并获得交易订单(可收货)
493 TradeOrderDO order = validateOrderReceivable(userId, id); 493 TradeOrderDO order = validateOrderReceivable(userId, id);
494 494
  495 + // 收货订单
  496 + receiveOrder0(order);
  497 + }
  498 +
  499 + @Override
  500 + public int receiveOrderBySystem() {
  501 + // 1. 查询过期的待支付订单
  502 + LocalDateTime expireTime = addTime(tradeOrderProperties.getReceiveExpireTime());
  503 + List<TradeOrderDO> orders = tradeOrderMapper.selectListByStatusAndDeliveryTimeLt(
  504 + TradeOrderStatusEnum.DELIVERED.getStatus(), expireTime);
  505 + if (CollUtil.isEmpty(orders)) {
  506 + return 0;
  507 + }
  508 +
  509 + // 2. 遍历执行,逐个取消
  510 + int count = 0;
  511 + for (TradeOrderDO order : orders) {
  512 + try {
  513 + getSelf().receiveOrderBySystem(order);
  514 + count ++;
  515 + } catch (Throwable e) {
  516 + log.error("[autoReceiveOrder][order({}) 自动收货订单异常]", order.getId(), e);
  517 + }
  518 + }
  519 + return count;
  520 + }
  521 +
  522 + /**
  523 + * 自动收货单个订单
  524 + *
  525 + * @param order 订单
  526 + */
  527 + @Transactional(rollbackFor = Exception.class)
  528 + @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.SYSTEM_RECEIVE)
  529 + public void receiveOrderBySystem(TradeOrderDO order) {
  530 + receiveOrder0(order);
  531 + }
  532 +
  533 + /**
  534 + * 收货订单的核心实现
  535 + *
  536 + * @param order 订单
  537 + */
  538 + private void receiveOrder0(TradeOrderDO order) {
495 // 更新 TradeOrderDO 状态为已完成 539 // 更新 TradeOrderDO 状态为已完成
496 int updateCount = tradeOrderMapper.updateByIdAndStatus(order.getId(), order.getStatus(), 540 int updateCount = tradeOrderMapper.updateByIdAndStatus(order.getId(), order.getStatus(),
497 new TradeOrderDO().setStatus(TradeOrderStatusEnum.COMPLETED.getStatus()).setReceiveTime(LocalDateTime.now())); 541 new TradeOrderDO().setStatus(TradeOrderStatusEnum.COMPLETED.getStatus()).setReceiveTime(LocalDateTime.now()));
@@ -499,14 +543,137 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { @@ -499,14 +543,137 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
499 throw exception(ORDER_RECEIVE_FAIL_STATUS_NOT_DELIVERED); 543 throw exception(ORDER_RECEIVE_FAIL_STATUS_NOT_DELIVERED);
500 } 544 }
501 545
502 - // TODO 芋艿:lili 发送订单变化的消息 546 + // 插入订单日志
  547 + TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), TradeOrderStatusEnum.COMPLETED.getStatus());
  548 + }
  549 +
  550 + /**
  551 + * 校验交易订单满足可售货的条件
  552 + *
  553 + * 1. 交易订单待收货
  554 + *
  555 + * @param userId 用户编号
  556 + * @param id 交易订单编号
  557 + * @return 交易订单
  558 + */
  559 + private TradeOrderDO validateOrderReceivable(Long userId, Long id) {
  560 + // 校验订单是否存在
  561 + TradeOrderDO order = tradeOrderMapper.selectByIdAndUserId(id, userId);
  562 + if (order == null) {
  563 + throw exception(ORDER_NOT_FOUND);
  564 + }
  565 + // 校验订单是否是待收货状态
  566 + if (!TradeOrderStatusEnum.isDelivered(order.getStatus())) {
  567 + throw exception(ORDER_RECEIVE_FAIL_STATUS_NOT_DELIVERED);
  568 + }
  569 + return order;
  570 + }
  571 +
  572 + @Override
  573 + @Transactional(rollbackFor = Exception.class)
  574 + @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.MEMBER_CANCEL)
  575 + public void cancelOrderByMember(Long userId, Long id) {
  576 + // 1.1 校验存在
  577 + TradeOrderDO order = tradeOrderMapper.selectOrderByIdAndUserId(id, userId);
  578 + if (order == null) {
  579 + throw exception(ORDER_NOT_FOUND);
  580 + }
  581 + // 1.2 校验状态
  582 + if (ObjectUtil.notEqual(order.getStatus(), TradeOrderStatusEnum.UNPAID.getStatus())) {
  583 + throw exception(ORDER_CANCEL_FAIL_STATUS_NOT_UNPAID);
  584 + }
  585 +
  586 + // 2. 取消订单
  587 + cancelOrder0(order, TradeOrderCancelTypeEnum.MEMBER_CANCEL);
  588 + }
  589 +
  590 + @Override
  591 + public int cancelOrderBySystem() {
  592 + // 1. 查询过期的待支付订单
  593 + LocalDateTime expireTime = addTime(tradeOrderProperties.getPayExpireTime());
  594 + List<TradeOrderDO> orders = tradeOrderMapper.selectListByStatusAndCreateTimeLt(
  595 + TradeOrderStatusEnum.UNPAID.getStatus(), expireTime);
  596 + if (CollUtil.isEmpty(orders)) {
  597 + return 0;
  598 + }
503 599
504 - // TODO 芋艿:lili 发送商品被购买完成的数据 600 + // 2. 遍历执行,逐个取消
  601 + int count = 0;
  602 + for (TradeOrderDO order : orders) {
  603 + try {
  604 + getSelf().cancelOrderBySystem(order);
  605 + count ++;
  606 + } catch (Throwable e) {
  607 + log.error("[autoCancelOrder][order({}) 过期订单异常]", order.getId(), e);
  608 + }
  609 + }
  610 + return count;
  611 + }
505 612
506 - // TODO 芋艿:销售佣金的记录; 613 + /**
  614 + * 自动取消单个订单
  615 + *
  616 + * @param order 订单
  617 + */
  618 + @Transactional(rollbackFor = Exception.class)
  619 + @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.SYSTEM_CANCEL)
  620 + public void cancelOrderBySystem(TradeOrderDO order) {
  621 + cancelOrder0(order, TradeOrderCancelTypeEnum.PAY_TIMEOUT);
  622 + }
507 623
508 - // 插入订单日志  
509 - TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), TradeOrderStatusEnum.COMPLETED.getStatus()); 624 + /**
  625 + * 取消订单的核心实现
  626 + *
  627 + * @param order 订单
  628 + * @param cancelType 取消类型
  629 + */
  630 + private void cancelOrder0(TradeOrderDO order, TradeOrderCancelTypeEnum cancelType) {
  631 + Long id = order.getId();
  632 + // 1. 更新 TradeOrderDO 状态为已取消
  633 + int updateCount = tradeOrderMapper.updateByIdAndStatus(id, order.getStatus(),
  634 + new TradeOrderDO().setStatus(TradeOrderStatusEnum.CANCELED.getStatus())
  635 + .setCancelType(cancelType.getType()).setCancelTime(LocalDateTime.now()));
  636 + if (updateCount == 0) {
  637 + throw exception(ORDER_CANCEL_FAIL_STATUS_NOT_UNPAID);
  638 + }
  639 +
  640 + // 2. TODO 活动相关库存回滚需要活动 id,活动 id 怎么获取?app 端能否传过来;回复:从订单里拿呀
  641 + tradeOrderHandlers.forEach(handler -> handler.rollback());
  642 +
  643 + // 3. 回滚库存
  644 + List<TradeOrderItemDO> orderItems = tradeOrderItemMapper.selectListByOrderId(id);
  645 + productSkuApi.updateSkuStock(TradeOrderConvert.INSTANCE.convert(orderItems));
  646 +
  647 + // 4. 回滚优惠券
  648 + if (order.getCouponId() != null && order.getCouponId() > 0) {
  649 + couponApi.returnUsedCoupon(order.getCouponId());
  650 + }
  651 +
  652 + // 5. 回滚积分(抵扣的)
  653 + addUserPoint(order.getUserId(), order.getUsePoint(), MemberPointBizTypeEnum.ORDER_CANCEL, order.getId());
  654 +
  655 + // 6. 增加订单日志
  656 + TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), TradeOrderStatusEnum.CANCELED.getStatus());
  657 + }
  658 +
  659 + @Override
  660 + @Transactional(rollbackFor = Exception.class)
  661 + @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.MEMBER_DELETE)
  662 + public void deleteOrder(Long userId, Long id) {
  663 + // 1.1 校验存在
  664 + TradeOrderDO order = tradeOrderMapper.selectOrderByIdAndUserId(id, userId);
  665 + if (order == null) {
  666 + throw exception(ORDER_NOT_FOUND);
  667 + }
  668 + // 1.2 校验状态
  669 + if (ObjectUtil.notEqual(order.getStatus(), TradeOrderStatusEnum.CANCELED.getStatus())) {
  670 + throw exception(ORDER_DELETE_FAIL_STATUS_NOT_CANCEL);
  671 + }
  672 + // 2. 删除订单
  673 + tradeOrderMapper.deleteById(id);
  674 +
  675 + // 3. 记录日志
  676 + TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), order.getStatus());
510 } 677 }
511 678
512 @Override 679 @Override
@@ -604,33 +771,13 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { @@ -604,33 +771,13 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
604 tradeOrderMapper.updateById(update); 771 tradeOrderMapper.updateById(update);
605 } 772 }
606 773
607 - /**  
608 - * 校验交易订单满足可售货的条件  
609 - *  
610 - * 1. 交易订单待收货  
611 - *  
612 - * @param userId 用户编号  
613 - * @param id 交易订单编号  
614 - * @return 交易订单  
615 - */  
616 - private TradeOrderDO validateOrderReceivable(Long userId, Long id) {  
617 - // 校验订单是否存在  
618 - TradeOrderDO order = tradeOrderMapper.selectByIdAndUserId(id, userId);  
619 - if (order == null) {  
620 - throw exception(ORDER_NOT_FOUND);  
621 - }  
622 - // 校验订单是否是待收货状态  
623 - if (!TradeOrderStatusEnum.isDelivered(order.getStatus())) {  
624 - throw exception(ORDER_RECEIVE_FAIL_STATUS_NOT_DELIVERED);  
625 - }  
626 - return order;  
627 - }  
628 -  
629 // =================== Order Item =================== 774 // =================== Order Item ===================
630 775
  776 + // TODO 疯狂:帮我重构下:
  777 + // 1. updateOrderItemAfterSaleStatus 拆分成三个方法:发起;同意;拒绝。原因是,职责更清晰,操作日志也更容易记录;
  778 +
631 @Override 779 @Override
632 @Transactional(rollbackFor = Exception.class) 780 @Transactional(rollbackFor = Exception.class)
633 - // TODO 芋艿:  
634 public void updateOrderItemAfterSaleStatus(Long id, Integer oldAfterSaleStatus, Integer newAfterSaleStatus, 781 public void updateOrderItemAfterSaleStatus(Long id, Integer oldAfterSaleStatus, Integer newAfterSaleStatus,
635 Long afterSaleId, Integer refundPrice) { 782 Long afterSaleId, Integer refundPrice) {
636 // 如果退款成功,则 refundPrice 非空 783 // 如果退款成功,则 refundPrice 非空
@@ -658,6 +805,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { @@ -658,6 +805,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
658 TradeOrderItemDO orderItem = tradeOrderItemMapper.selectById(id); 805 TradeOrderItemDO orderItem = tradeOrderItemMapper.selectById(id);
659 TradeOrderDO order = tradeOrderMapper.selectById(orderItem.getOrderId()); 806 TradeOrderDO order = tradeOrderMapper.selectById(orderItem.getOrderId());
660 Integer orderRefundPrice = order.getRefundPrice() + refundPrice; 807 Integer orderRefundPrice = order.getRefundPrice() + refundPrice;
  808 + // TODO @疯狂:809 到 817 改成:cancelOrderByAfterSale:相当于全部售后成功后,就是要取消胆子;
661 if (isAllOrderItemAfterSaleSuccess(order.getId())) { // 如果都售后成功,则需要取消订单 809 if (isAllOrderItemAfterSaleSuccess(order.getId())) { // 如果都售后成功,则需要取消订单
662 tradeOrderMapper.updateById(new TradeOrderDO().setId(order.getId()) 810 tradeOrderMapper.updateById(new TradeOrderDO().setId(order.getId())
663 .setRefundStatus(TradeOrderRefundStatusEnum.ALL.getStatus()).setRefundPrice(orderRefundPrice).setRefundPoint(order.getRefundPoint() + orderItem.getUsePoint()) 811 .setRefundStatus(TradeOrderRefundStatusEnum.ALL.getStatus()).setRefundPrice(orderRefundPrice).setRefundPoint(order.getRefundPoint() + orderItem.getUsePoint())
@@ -667,7 +815,6 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { @@ -667,7 +815,6 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
667 815
668 // TODO 芋艿:要不要退优惠劵 816 // TODO 芋艿:要不要退优惠劵
669 817
670 - // TODO 芋艿:站内信?  
671 } else { // 如果部分售后,则更新退款金额 818 } else { // 如果部分售后,则更新退款金额
672 tradeOrderMapper.updateById(new TradeOrderDO().setId(order.getId()) 819 tradeOrderMapper.updateById(new TradeOrderDO().setId(order.getId())
673 .setRefundStatus(TradeOrderRefundStatusEnum.PART.getStatus()).setRefundPrice(orderRefundPrice)); 820 .setRefundStatus(TradeOrderRefundStatusEnum.PART.getStatus()).setRefundPrice(orderRefundPrice));
@@ -676,6 +823,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { @@ -676,6 +823,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
676 // TODO 芋艿:这块扣减规则,需要在考虑下 823 // TODO 芋艿:这块扣减规则,需要在考虑下
677 // 售后成功后,执行数据回滚逻辑 824 // 售后成功后,执行数据回滚逻辑
678 if (Objects.equals(newAfterSaleStatus, TradeOrderItemAfterSaleStatusEnum.SUCCESS.getStatus())) { 825 if (Objects.equals(newAfterSaleStatus, TradeOrderItemAfterSaleStatusEnum.SUCCESS.getStatus())) {
  826 + // TODO @疯狂:这里库存也要扣减下;
679 // 扣减用户积分(赠送的) 827 // 扣减用户积分(赠送的)
680 reduceUserPoint(order.getUserId(), orderItem.getGivePoint(), MemberPointBizTypeEnum.AFTER_SALE_DEDUCT_GIVE, afterSaleId); 828 reduceUserPoint(order.getUserId(), orderItem.getGivePoint(), MemberPointBizTypeEnum.AFTER_SALE_DEDUCT_GIVE, afterSaleId);
681 // 增加用户积分(返还抵扣) 829 // 增加用户积分(返还抵扣)
@@ -723,113 +871,6 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { @@ -723,113 +871,6 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
723 return comment; 871 return comment;
724 } 872 }
725 873
726 - @Override  
727 - @Transactional(rollbackFor = Exception.class)  
728 - @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.MEMBER_CANCEL)  
729 - public void cancelOrder(Long userId, Long id) {  
730 - // 1.1 校验存在  
731 - TradeOrderDO order = tradeOrderMapper.selectOrderByIdAndUserId(id, userId);  
732 - if (order == null) {  
733 - throw exception(ORDER_NOT_FOUND);  
734 - }  
735 - // 1.2 校验状态  
736 - if (ObjectUtil.notEqual(order.getStatus(), TradeOrderStatusEnum.UNPAID.getStatus())) {  
737 - throw exception(ORDER_CANCEL_FAIL_STATUS_NOT_UNPAID);  
738 - }  
739 -  
740 - // 2. 取消订单  
741 - cancelOrder0(order, TradeOrderCancelTypeEnum.MEMBER_CANCEL);  
742 - }  
743 -  
744 - @Override  
745 - public int autoCancelOrder() {  
746 - // 1. 查询过期的待支付订单  
747 - LocalDateTime expireTime = addTime(tradeOrderProperties.getExpireTime());  
748 - List<TradeOrderDO> orders = tradeOrderMapper.selectListByStatusAndCreateTimeLt(  
749 - TradeOrderStatusEnum.UNPAID.getStatus(), expireTime);  
750 - if (CollUtil.isEmpty(orders)) {  
751 - return 0;  
752 - }  
753 -  
754 - // 2. 遍历执行,逐个取消  
755 - int count = 0;  
756 - for (TradeOrderDO order : orders) {  
757 - try {  
758 - getSelf().autoCancelOrder(order);  
759 - count ++;  
760 - } catch (Throwable e) {  
761 - log.error("[autoCancelOrder][order({}) 过期订单异常]", order.getId(), e);  
762 - }  
763 - }  
764 - return count;  
765 - }  
766 -  
767 - /**  
768 - * 自动取消单个订单  
769 - *  
770 - * @param order 订单  
771 - */  
772 - @Transactional(rollbackFor = Exception.class)  
773 - @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.SYSTEM_CANCEL)  
774 - public void autoCancelOrder(TradeOrderDO order) {  
775 - cancelOrder0(order, TradeOrderCancelTypeEnum.PAY_TIMEOUT);  
776 - }  
777 -  
778 - /**  
779 - * 取消订单的核心实现  
780 - *  
781 - * @param order 订单  
782 - * @param cancelType 取消类型  
783 - */  
784 - private void cancelOrder0(TradeOrderDO order, TradeOrderCancelTypeEnum cancelType) {  
785 - Long id = order.getId();  
786 - // 1. 更新 TradeOrderDO 状态为已取消  
787 - int updateCount = tradeOrderMapper.updateByIdAndStatus(id, order.getStatus(),  
788 - new TradeOrderDO().setStatus(TradeOrderStatusEnum.CANCELED.getStatus())  
789 - .setCancelType(cancelType.getType()).setCancelTime(LocalDateTime.now()));  
790 - if (updateCount == 0) {  
791 - throw exception(ORDER_CANCEL_FAIL_STATUS_NOT_UNPAID);  
792 - }  
793 -  
794 - // 2. TODO 活动相关库存回滚需要活动 id,活动 id 怎么获取?app 端能否传过来;回复:从订单里拿呀  
795 - tradeOrderHandlers.forEach(handler -> handler.rollback());  
796 -  
797 - // 3. 回滚库存  
798 - List<TradeOrderItemDO> orderItems = tradeOrderItemMapper.selectListByOrderId(id);  
799 - productSkuApi.updateSkuStock(TradeOrderConvert.INSTANCE.convert(orderItems));  
800 -  
801 - // 4. 回滚优惠券  
802 - if (order.getCouponId() != null && order.getCouponId() > 0) {  
803 - couponApi.returnUsedCoupon(order.getCouponId());  
804 - }  
805 -  
806 - // 5. 回滚积分(抵扣的)  
807 - addUserPoint(order.getUserId(), order.getUsePoint(), MemberPointBizTypeEnum.ORDER_CANCEL, order.getId());  
808 -  
809 - // 6. 增加订单日志  
810 - TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), TradeOrderStatusEnum.CANCELED.getStatus());  
811 - }  
812 -  
813 - @Override  
814 - @Transactional(rollbackFor = Exception.class)  
815 - @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.MEMBER_DELETE)  
816 - public void deleteOrder(Long userId, Long id) {  
817 - // 1.1 校验存在  
818 - TradeOrderDO order = tradeOrderMapper.selectOrderByIdAndUserId(id, userId);  
819 - if (order == null) {  
820 - throw exception(ORDER_NOT_FOUND);  
821 - }  
822 - // 1.2 校验状态  
823 - if (ObjectUtil.notEqual(order.getStatus(), TradeOrderStatusEnum.CANCELED.getStatus())) {  
824 - throw exception(ORDER_DELETE_FAIL_STATUS_NOT_CANCEL);  
825 - }  
826 - // 2. 删除订单  
827 - tradeOrderMapper.deleteById(id);  
828 -  
829 - // 3. 记录日志  
830 - TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), order.getStatus());  
831 - }  
832 -  
833 /** 874 /**
834 * 判断指定订单的所有订单项,是不是都售后成功 875 * 判断指定订单的所有订单项,是不是都售后成功
835 * 876 *
@@ -842,6 +883,8 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { @@ -842,6 +883,8 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
842 TradeOrderItemAfterSaleStatusEnum.SUCCESS.getStatus())); 883 TradeOrderItemAfterSaleStatusEnum.SUCCESS.getStatus()));
843 } 884 }
844 885
  886 + // =================== 营销相关的操作 ===================
  887 +
845 @Async 888 @Async
846 protected void addUserExperienceAsync(Long userId, Integer payPrice, Long orderId) { 889 protected void addUserExperienceAsync(Long userId, Integer payPrice, Long orderId) {
847 int bizType = MemberExperienceBizTypeEnum.ORDER.getType(); 890 int bizType = MemberExperienceBizTypeEnum.ORDER.getType();
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointGiveCalculator.java
@@ -16,6 +16,7 @@ import java.util.Optional; @@ -16,6 +16,7 @@ import java.util.Optional;
16 16
17 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList; 17 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList;
18 18
  19 +// TODO @疯狂:这个可以搞个单测;
19 /** 20 /**
20 * 赠送积分的 {@link TradePriceCalculator} 实现类 21 * 赠送积分的 {@link TradePriceCalculator} 实现类
21 * 22 *
@@ -25,6 +26,7 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils. @@ -25,6 +26,7 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.
25 @Order(TradePriceCalculator.ORDER_POINT_GIVE) 26 @Order(TradePriceCalculator.ORDER_POINT_GIVE)
26 @Slf4j 27 @Slf4j
27 public class TradePointGiveCalculator implements TradePriceCalculator { 28 public class TradePointGiveCalculator implements TradePriceCalculator {
  29 +
28 @Resource 30 @Resource
29 private MemberPointApi memberPointApi; 31 private MemberPointApi memberPointApi;
30 32
@@ -54,9 +56,10 @@ public class TradePointGiveCalculator implements TradePriceCalculator { @@ -54,9 +56,10 @@ public class TradePointGiveCalculator implements TradePriceCalculator {
54 TradePriceCalculateRespBO.OrderItem orderItem = orderItems.get(i); 56 TradePriceCalculateRespBO.OrderItem orderItem = orderItems.get(i);
55 // 商品可能赠送了积分,所以这里要加上 57 // 商品可能赠送了积分,所以这里要加上
56 orderItem.setGivePoint(orderItem.getGivePoint() + dividePoints.get(i)); 58 orderItem.setGivePoint(orderItem.getGivePoint() + dividePoints.get(i));
57 - TradePriceCalculatorHelper.recountPayPrice(orderItem); 59 + TradePriceCalculatorHelper.recountPayPrice(orderItem); // TODO @疯狂:这个应该不用调用哇?不影响支付金额
58 } 60 }
59 // 3.3 更新订单赠送积分 61 // 3.3 更新订单赠送积分
60 TradePriceCalculatorHelper.recountAllGivePoint(result); 62 TradePriceCalculatorHelper.recountAllGivePoint(result);
61 } 63 }
  64 +
62 } 65 }
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePointUsePriceCalculator.java
@@ -20,6 +20,7 @@ import java.util.List; @@ -20,6 +20,7 @@ import java.util.List;
20 20
21 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList; 21 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList;
22 22
  23 +// TODO @疯狂:搞个单测,嘿嘿;
23 /** 24 /**
24 * 使用积分的 {@link TradePriceCalculator} 实现类 25 * 使用积分的 {@link TradePriceCalculator} 实现类
25 * 26 *
@@ -29,6 +30,7 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils. @@ -29,6 +30,7 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.
29 @Order(TradePriceCalculator.ORDER_POINT_USE) 30 @Order(TradePriceCalculator.ORDER_POINT_USE)
30 @Slf4j 31 @Slf4j
31 public class TradePointUsePriceCalculator implements TradePriceCalculator { 32 public class TradePointUsePriceCalculator implements TradePriceCalculator {
  33 +
32 @Resource 34 @Resource
33 private MemberPointApi memberPointApi; 35 private MemberPointApi memberPointApi;
34 @Resource 36 @Resource
@@ -48,13 +50,14 @@ public class TradePointUsePriceCalculator implements TradePriceCalculator { @@ -48,13 +50,14 @@ public class TradePointUsePriceCalculator implements TradePriceCalculator {
48 } 50 }
49 // 1.3 校验用户积分余额 51 // 1.3 校验用户积分余额
50 MemberUserRespDTO user = memberUserApi.getUser(param.getUserId()); 52 MemberUserRespDTO user = memberUserApi.getUser(param.getUserId());
51 - if (user.getPoint() == null || user.getPoint() < 0) { 53 + if (user.getPoint() == null || user.getPoint() <= 0) {
52 return; 54 return;
53 } 55 }
54 56
55 // 2.1 计算积分优惠金额 57 // 2.1 计算积分优惠金额
  58 + // TODO @疯狂:如果计算出来,优惠金额为 0,那是不是不用执行后续逻辑哈
56 int pointPrice = calculatePointPrice(config, user.getPoint(), result); 59 int pointPrice = calculatePointPrice(config, user.getPoint(), result);
57 - // 2.1 计算分摊的积分、抵扣金额 60 + // 2.2 计算分摊的积分、抵扣金额
58 List<TradePriceCalculateRespBO.OrderItem> orderItems = filterList(result.getItems(), TradePriceCalculateRespBO.OrderItem::getSelected); 61 List<TradePriceCalculateRespBO.OrderItem> orderItems = filterList(result.getItems(), TradePriceCalculateRespBO.OrderItem::getSelected);
59 List<Integer> dividePointPrices = TradePriceCalculatorHelper.dividePrice(orderItems, pointPrice); 62 List<Integer> dividePointPrices = TradePriceCalculatorHelper.dividePrice(orderItems, pointPrice);
60 List<Integer> divideUsePoints = TradePriceCalculatorHelper.dividePrice(orderItems, result.getUsePoint()); 63 List<Integer> divideUsePoints = TradePriceCalculatorHelper.dividePrice(orderItems, result.getUsePoint());
@@ -74,7 +77,9 @@ public class TradePointUsePriceCalculator implements TradePriceCalculator { @@ -74,7 +77,9 @@ public class TradePointUsePriceCalculator implements TradePriceCalculator {
74 TradePriceCalculatorHelper.recountAllPrice(result); 77 TradePriceCalculatorHelper.recountAllPrice(result);
75 } 78 }
76 79
  80 + // TODO @疯狂:这个最好是 is 开头;因为 check 或者 validator,更多失败,会抛出异常;
77 private boolean checkDeductPointEnable(MemberPointConfigRespDTO config) { 81 private boolean checkDeductPointEnable(MemberPointConfigRespDTO config) {
  82 + // TODO @疯狂:这个要不直接写成 return config != null && config .... 多行这样一个形式;
78 if (config == null) { 83 if (config == null) {
79 return false; 84 return false;
80 } 85 }
@@ -93,7 +98,7 @@ public class TradePointUsePriceCalculator implements TradePriceCalculator { @@ -93,7 +98,7 @@ public class TradePointUsePriceCalculator implements TradePriceCalculator {
93 } 98 }
94 // 积分优惠金额(分) 99 // 积分优惠金额(分)
95 int pointPrice = usePoint * config.getTradeDeductUnitPrice(); 100 int pointPrice = usePoint * config.getTradeDeductUnitPrice();
96 - // 0元购!!!:用户积分比较多时,积分可以抵扣的金额要大于支付金额, 这时需要根据支付金额反推使用多少积分 101 + // 0 元购!!!:用户积分比较多时,积分可以抵扣的金额要大于支付金额,这时需要根据支付金额反推使用多少积分
97 if (result.getPrice().getPayPrice() < pointPrice) { 102 if (result.getPrice().getPayPrice() < pointPrice) {
98 pointPrice = result.getPrice().getPayPrice(); 103 pointPrice = result.getPrice().getPayPrice();
99 // 反推需要扣除的积分 104 // 反推需要扣除的积分
@@ -103,7 +108,7 @@ public class TradePointUsePriceCalculator implements TradePriceCalculator { @@ -103,7 +108,7 @@ public class TradePointUsePriceCalculator implements TradePriceCalculator {
103 } 108 }
104 // 记录使用的积分 109 // 记录使用的积分
105 result.setUsePoint(usePoint); 110 result.setUsePoint(usePoint);
106 -  
107 return pointPrice; 111 return pointPrice;
108 } 112 }
  113 +
109 } 114 }
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculator.java
@@ -21,11 +21,13 @@ public interface TradePriceCalculator { @@ -21,11 +21,13 @@ public interface TradePriceCalculator {
21 /** 21 /**
22 * 快递运费的计算 22 * 快递运费的计算
23 * 23 *
24 - * 放在各种营销活动、优惠劵后面 TODO 24 + * 放在各种营销活动、优惠劵后面
25 */ 25 */
26 int ORDER_DELIVERY = 50; 26 int ORDER_DELIVERY = 50;
27 /** 27 /**
28 * 赠送积分,放最后 28 * 赠送积分,放最后
  29 + *
  30 + * 放在 {@link #ORDER_DELIVERY} 后面的原因,是运费也会产生费用,需要赠送对应积分
29 */ 31 */
30 int ORDER_POINT_GIVE = 999; 32 int ORDER_POINT_GIVE = 999;
31 33
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculatorHelper.java
@@ -199,6 +199,8 @@ public class TradePriceCalculatorHelper { @@ -199,6 +199,8 @@ public class TradePriceCalculatorHelper {
199 /** 199 /**
200 * 按照支付金额,返回每个订单项的分摊金额数组 200 * 按照支付金额,返回每个订单项的分摊金额数组
201 * 201 *
  202 + * 实际上 price 不仅仅可以传递的是金额,也可以是积分。因为它的实现逻辑,就是根据 payPrice 做分摊而已
  203 + *
202 * @param orderItems 订单项数组 204 * @param orderItems 订单项数组
203 * @param price 金额 205 * @param price 金额
204 * @return 分摊金额数组,和传入的 orderItems 一一对应 206 * @return 分摊金额数组,和传入的 orderItems 一一对应
yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceTest.java
@@ -87,7 +87,7 @@ public class TradeOrderUpdateServiceTest extends BaseDbUnitTest { @@ -87,7 +87,7 @@ public class TradeOrderUpdateServiceTest extends BaseDbUnitTest {
87 @BeforeEach 87 @BeforeEach
88 public void setUp() { 88 public void setUp() {
89 when(tradeOrderProperties.getAppId()).thenReturn(888L); 89 when(tradeOrderProperties.getAppId()).thenReturn(888L);
90 - when(tradeOrderProperties.getExpireTime()).thenReturn(Duration.ofDays(1)); 90 + when(tradeOrderProperties.getPayExpireTime()).thenReturn(Duration.ofDays(1));
91 } 91 }
92 92
93 @Test 93 @Test
@@ -306,7 +306,7 @@ public class TradeOrderUpdateServiceTest extends BaseDbUnitTest { @@ -306,7 +306,7 @@ public class TradeOrderUpdateServiceTest extends BaseDbUnitTest {
306 // mock 方法(支付单) 306 // mock 方法(支付单)
307 307
308 // 调用 308 // 调用
309 - tradeOrderUpdateService.receiveOrder(userId, id); 309 + tradeOrderUpdateService.receiveOrderByMember(userId, id);
310 // 断言 310 // 断言
311 TradeOrderDO dbOrder = tradeOrderMapper.selectById(1L); 311 TradeOrderDO dbOrder = tradeOrderMapper.selectById(1L);
312 assertEquals(dbOrder.getStatus(), TradeOrderStatusEnum.COMPLETED.getStatus()); 312 assertEquals(dbOrder.getStatus(), TradeOrderStatusEnum.COMPLETED.getStatus());
yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/point/MemberPointApi.java
@@ -12,6 +12,7 @@ import javax.validation.constraints.Min; @@ -12,6 +12,7 @@ import javax.validation.constraints.Min;
12 */ 12 */
13 public interface MemberPointApi { 13 public interface MemberPointApi {
14 14
  15 + // TODO @疯狂:这个我们要不要搞成通用的会员配置?MemberConfig?
15 /** 16 /**
16 * 获得积分配置 17 * 获得积分配置
17 * 18 *
yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/point/dto/MemberPointConfigRespDTO.java
@@ -9,6 +9,7 @@ import lombok.Data; @@ -9,6 +9,7 @@ import lombok.Data;
9 */ 9 */
10 @Data 10 @Data
11 public class MemberPointConfigRespDTO { 11 public class MemberPointConfigRespDTO {
  12 +
12 /** 13 /**
13 * 积分抵扣开关 14 * 积分抵扣开关
14 */ 15 */
@@ -27,4 +28,5 @@ public class MemberPointConfigRespDTO { @@ -27,4 +28,5 @@ public class MemberPointConfigRespDTO {
27 * 1 元赠送多少分 28 * 1 元赠送多少分
28 */ 29 */
29 private Integer tradeGivePoint; 30 private Integer tradeGivePoint;
  31 +
30 } 32 }
yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/user/dto/MemberUserRespDTO.java
@@ -51,4 +51,5 @@ public class MemberUserRespDTO { @@ -51,4 +51,5 @@ public class MemberUserRespDTO {
51 * 积分 51 * 积分
52 */ 52 */
53 private Integer point; 53 private Integer point;
  54 +
54 } 55 }
yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/enums/point/MemberPointBizTypeEnum.java
@@ -17,11 +17,11 @@ import java.util.Objects; @@ -17,11 +17,11 @@ import java.util.Objects;
17 public enum MemberPointBizTypeEnum implements IntArrayValuable { 17 public enum MemberPointBizTypeEnum implements IntArrayValuable {
18 18
19 SIGN(1, "签到", "签到获得 {} 积分", true), 19 SIGN(1, "签到", "签到获得 {} 积分", true),
20 - ORDER_REWARD(10, "订单奖励", "下单获得 {} 积分", true),  
21 - ORDER_CANCEL(11, "订单取消", "订单取消,退还 {} 积分", true), // 退回积分  
22 - ORDER_USE(12, "订单使用", "下单使用 {} 积分", false), // 扣减积分  
23 - AFTER_SALE_REFUND_USED(13, "订单退款", "订单退款,退还 {} 积分", true), // 退回积分  
24 - AFTER_SALE_DEDUCT_GIVE(14, "订单退款", "订单退款,扣除赠送的 {} 积分", false), // 扣减积分 20 + ORDER_GIVE(10, "订单奖励", "下单获得 {} 积分", true), // 支付订单时,赠送积分
  21 + ORDER_CANCEL(11, "订单取消", "订单取消,退还 {} 积分", true), // 取消订单时,退回积分
  22 + ORDER_USE(12, "订单使用", "下单使用 {} 积分", false), // 下单时,扣减积分
  23 + AFTER_SALE_REFUND_USED(13, "订单退款", "订单退款,退还 {} 积分", true), // 售后订单成功时,退回积分(对应 ORDER_USE 操作)
  24 + AFTER_SALE_DEDUCT_GIVE(14, "订单退款", "订单退款,扣除赠送的 {} 积分", false), // 售后订单成功时,扣减积分(对应 ORDER_GIVE 操作)
25 ; 25 ;
26 26
27 /** 27 /**
yudao-server/src/main/resources/application.yaml
@@ -203,7 +203,8 @@ yudao: @@ -203,7 +203,8 @@ yudao:
203 trade: 203 trade:
204 order: 204 order:
205 app-id: 1 # 商户编号 205 app-id: 1 # 商户编号
206 - expire-time: 2h # 支付的过期时间 206 + pay-expire-time: 2h # 支付的过期时间
  207 + receive-expire-time: 14d # 收货的过期时间
207 express: 208 express:
208 client: kd_niao 209 client: kd_niao
209 kd-niao: 210 kd-niao: