Commit cd2bc112cc4a12e0172beaa99f4ed6224d391669

Authored by YunaiV
1 parent ee1d362a

trade:【交易售后】完善发起、同意、不同意、收货、拒绝收货、退款的逻辑

Showing 15 changed files with 261 additions and 192 deletions
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java
... ... @@ -32,11 +32,9 @@ public interface ErrorCodeConstants {
32 32 ErrorCode AFTER_SALE_CREATE_FAIL_ORDER_ITEM_APPLIED = new ErrorCode(1011000105, "订单项已申请售后,无法重复申请");
33 33 ErrorCode AFTER_SALE_AUDIT_FAIL_STATUS_NOT_APPLY = new ErrorCode(1011000106, "审批失败,售后状态不处于审批中");
34 34 ErrorCode AFTER_SALE_UPDATE_STATUS_FAIL = new ErrorCode(1011000107, "操作售后单失败,请刷新后重试");
35   - ErrorCode AFTER_SALE_DELIVERY_FAIL_STATUS_NOT_SELLER_PASS = new ErrorCode(1011000108, "退货失败,售后单状态不处于【待买家退货】");
36   - ErrorCode AFTER_SALE_CONFIRM_FAIL_STATUS_NOT_BUYER_RETURN = new ErrorCode(1011000109, "确认收货失败,售后单状态不处于【待确认收货】");
37   - ErrorCode AFTER_SALE_REFUND_FAIL_PAY_REFUND_NOT_FOUND = new ErrorCode(1011000110, "退款失败,支付退款单不存在");
38   - ErrorCode AFTER_SALE_REFUND_FAIL_PAY_REFUND_STATUS_NOT_SUCCESS = new ErrorCode(1011000111, "退款失败,支付退款单状态不是【成功】");
39   - ErrorCode AFTER_SALE_REFUND_FAIL_STATUS_NOT_WAIT_REFUND = new ErrorCode(1011000112, "退款失败,售后单状态不是【待退款】");
  35 + ErrorCode AFTER_SALE_DELIVERY_FAIL_STATUS_NOT_SELLER_AGREE = new ErrorCode(1011000108, "退货失败,售后单状态不处于【待买家退货】");
  36 + ErrorCode AFTER_SALE_CONFIRM_FAIL_STATUS_NOT_BUYER_DELIVERY = new ErrorCode(1011000109, "确认收货失败,售后单状态不处于【待确认收货】");
  37 + ErrorCode AFTER_SALE_REFUND_FAIL_STATUS_NOT_WAIT_REFUND = new ErrorCode(1011000110, "退款失败,售后单状态不是【待退款】");
40 38  
41 39 // ========== Cart 模块 1-011-001-000 ==========
42 40 ErrorCode CARD_ITEM_NOT_FOUND = new ErrorCode(1011002000, "购物车项不存在");
... ...
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/aftersale/TradeAfterSaleStatusEnum.java
... ... @@ -15,14 +15,14 @@ import lombok.Getter;
15 15 public enum TradeAfterSaleStatusEnum {
16 16  
17 17 APPLY(10,"申请中"),
18   - SELLER_PASS(20, "已通过"), // 卖家通过售后
19   - BUYER_RETURN(30,"待卖家收货"), // 买家退货,等待卖家收货
20   - WAIT_REFUND(40, "等待平台退款"), // 卖家收货,等待平台退款
  18 + SELLER_AGREE(20, "卖家通过"), // 卖家通过售后
  19 + BUYER_DELIVERY(30,"待卖家收货"), // 买家已退货,等待卖家收货
  20 + WAIT_REFUND(40, "等待平台退款"), // 卖家已收货,等待平台退款
21 21 COMPLETE(50, "完成"), // 完成退款
22 22  
23 23 BUYER_CANCEL(61, "买家取消售后"),
24   - SELLER_REFUSE(62,"已拒绝"), // 卖家拒绝售后
25   - SELLER_TERMINATION(63,"卖家终止售后"), // 卖家拒绝收货,终止售后
  24 + SELLER_DISAGREE(62,"卖家拒绝"), // 卖家拒绝售后
  25 + SELLER_REFUSE(63,"卖家拒绝收货"), // 卖家拒绝收货,终止售后
26 26 ;
27 27  
28 28 /**
... ...
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderRefundStatusEnum.java renamed to yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderAfterSaleStatusEnum.java
... ... @@ -4,13 +4,13 @@ import lombok.Getter;
4 4 import lombok.RequiredArgsConstructor;
5 5  
6 6 /**
7   - * 交易订单 - 退款状态
  7 + * 交易订单 - 售后状态
8 8 *
9 9 * @author Sin
10 10 */
11 11 @RequiredArgsConstructor
12 12 @Getter
13   -public enum TradeOrderRefundStatusEnum {
  13 +public enum TradeOrderAfterSaleStatusEnum {
14 14  
15 15 NONE(0, "未退款"),
16 16 PART(1, "部分退款"),
... ...
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderCancelTypeEnum.java
... ... @@ -13,9 +13,9 @@ import lombok.RequiredArgsConstructor;
13 13 public enum TradeOrderCancelTypeEnum {
14 14  
15 15 PAY_TIMEOUT(10, "超时未支付"),
16   - REFUND_CLOSE(20, "退款关闭"),
  16 + AFTER_SALE_CLOSE(20, "退款关闭"),
17 17 MEMBER_CANCEL(30, "买家取消"),
18   - PAY_ON_DELIVERY(40, "已通过货到付款交易"),;
  18 + PAY_ON_DELIVERY(40, "已通过货到付款交易"),; // TODO 芋艿:这个类型,是不是可以去掉
19 19  
20 20 /**
21 21 * 关闭类型
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/TradeAfterSaleController.java
1 1 package cn.iocoder.yudao.module.trade.controller.admin.aftersale;
2 2  
3 3 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4   -import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleAuditReqVO;
5   -import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleConfirmReqVO;
  4 +import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleDisagreeReqVO;
6 5 import cn.iocoder.yudao.module.trade.service.aftersale.TradeAfterSaleService;
7 6 import io.swagger.annotations.Api;
8 7 import io.swagger.annotations.ApiImplicitParam;
... ... @@ -13,7 +12,6 @@ import org.springframework.validation.annotation.Validated;
13 12 import org.springframework.web.bind.annotation.*;
14 13  
15 14 import javax.annotation.Resource;
16   -import javax.annotation.security.PermitAll;
17 15  
18 16 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
19 17 import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
... ... @@ -29,28 +27,38 @@ public class TradeAfterSaleController {
29 27 @Resource
30 28 private TradeAfterSaleService afterSaleService;
31 29  
32   - @PutMapping("/audit")
33   - @ApiOperation("审批售后")
34   - @PreAuthorize("@ss.hasPermission('trade:after-sale:audit')")
35   - public CommonResult<Boolean> auditAfterSale(@RequestBody TradeAfterSaleAuditReqVO auditReqVO) {
36   - afterSaleService.auditAfterSale(getLoginUserId(), getClientIP(), auditReqVO);
  30 + @PutMapping("/agree")
  31 + @ApiOperation("同意售后")
  32 + @ApiImplicitParam(name = "id", value = "售后编号", required = true, example = "1")
  33 + @PreAuthorize("@ss.hasPermission('trade:after-sale:agree')")
  34 + public CommonResult<Boolean> agreeAfterSale(@RequestParam("id") Long id) {
  35 + afterSaleService.agreeAfterSale(getLoginUserId(), id);
37 36 return success(true);
38 37 }
39 38  
40   - @PutMapping("/confirm")
  39 + @PutMapping("/disagree")
  40 + @ApiOperation("拒绝售后")
  41 + @PreAuthorize("@ss.hasPermission('trade:after-sale:disagree')")
  42 + public CommonResult<Boolean> disagreeAfterSale(@RequestBody TradeAfterSaleDisagreeReqVO confirmReqVO) {
  43 + afterSaleService.disagreeAfterSale(getLoginUserId(), confirmReqVO);
  44 + return success(true);
  45 + }
  46 +
  47 + @PutMapping("/receive")
41 48 @ApiOperation("确认收货")
42   - @PreAuthorize("@ss.hasPermission('trade:after-sale:audit')")
43   - public CommonResult<Boolean> confirmAfterSale(@RequestBody TradeAfterSaleConfirmReqVO confirmReqVO) {
44   - afterSaleService.confirmAfterSale(getLoginUserId(), getClientIP(), confirmReqVO);
  49 + @ApiImplicitParam(name = "id", value = "售后编号", required = true, example = "1")
  50 + @PreAuthorize("@ss.hasPermission('trade:after-sale:receive')")
  51 + public CommonResult<Boolean> receiveAfterSale(@RequestParam("id") Long id) {
  52 + afterSaleService.receiveAfterSale(getLoginUserId(), id);
45 53 return success(true);
46 54 }
47 55  
48 56 @PostMapping("/refund")
49   - @ApiOperation(value = "确认退款", notes = "提供给【pay】支付服务,退款成功后进行回调")
50   - @ApiImplicitParam(name = "payRefundId", value = "支付退款编号", required = true, example = "18888")
51   - @PermitAll
52   - public CommonResult<Boolean> refundAfterSale(@RequestParam("payRefundId") Long payRefundId) {
53   - afterSaleService.refundAfterSale(payRefundId);
  57 + @ApiOperation(value = "确认退款")
  58 + @ApiImplicitParam(name = "id", value = "售后编号", required = true, example = "1")
  59 + @PreAuthorize("@ss.hasPermission('trade:after-sale:refund')")
  60 + public CommonResult<Boolean> refundAfterSale(@RequestParam("id") Long id) {
  61 + afterSaleService.refundAfterSale(getLoginUserId(), getClientIP(), id);
54 62 return success(true);
55 63 }
56 64  
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSaleAuditReqVO.java renamed to yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSaleDisagreeReqVO.java
... ... @@ -4,22 +4,19 @@ import io.swagger.annotations.ApiModel;
4 4 import io.swagger.annotations.ApiModelProperty;
5 5 import lombok.Data;
6 6  
  7 +import javax.validation.constraints.NotEmpty;
7 8 import javax.validation.constraints.NotNull;
8 9  
9   -@ApiModel("管理后台 - 交易售后审批 Request VO")
  10 +@ApiModel("管理后台 - 交易售后拒绝 Request VO")
10 11 @Data
11   -public class TradeAfterSaleAuditReqVO {
  12 +public class TradeAfterSaleDisagreeReqVO {
12 13  
13 14 @ApiModelProperty(value = "售后编号", required = true, example = "1024")
14 15 @NotNull(message = "售后编号不能为空")
15 16 private Long id;
16 17  
17   - @ApiModelProperty(value = "审批结果", required = true, example = "true",
18   - notes = "true - 通过;false - 不通过")
19   - @NotNull(message = "审批结果不能为空")
20   - private Boolean pass;
21   -
22   - @ApiModelProperty(value = "审批备注", example = "你猜")
  18 + @ApiModelProperty(value = "审批备注", required = true, example = "你猜")
  19 + @NotEmpty(message = "审批备注不能为空")
23 20 private String auditReason;
24 21  
25 22 }
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSaleConfirmReqVO.java renamed to yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSaleRefuseReqVO.java
... ... @@ -6,20 +6,16 @@ import lombok.Data;
6 6  
7 7 import javax.validation.constraints.NotNull;
8 8  
9   -@ApiModel("管理后台 - 交易售后确认收货 Request VO")
  9 +@ApiModel("管理后台 - 交易售后拒绝收货 Request VO")
10 10 @Data
11   -public class TradeAfterSaleConfirmReqVO {
  11 +public class TradeAfterSaleRefuseReqVO {
12 12  
13 13 @ApiModelProperty(value = "售后编号", required = true, example = "1024")
14 14 @NotNull(message = "售后编号不能为空")
15 15 private Long id;
16 16  
17   - @ApiModelProperty(value = "收货结果", required = true, example = "true",
18   - notes = "true - 确认收货;false - 拒绝收货")
19   - @NotNull(message = "审批结果不能为空")
20   - private Boolean pass;
21   -
22   - @ApiModelProperty(value = "收货备注", example = "你猜")
23   - private String receiptMemo;
  17 + @ApiModelProperty(value = "收货备注", required = true, example = "你猜")
  18 + @NotNull(message = "收货备注不能为空")
  19 + private String refuseMemo;
24 20  
25 21 }
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/aftersale/TradeAfterSaleDO.java
... ... @@ -86,6 +86,8 @@ public class TradeAfterSaleDO extends BaseDO {
86 86 private Long auditUserId;
87 87 /**
88 88 * 审批备注
  89 + *
  90 + * 注意,只有审批不通过才会填写
89 91 */
90 92 private String auditReason;
91 93  
... ... @@ -132,8 +134,6 @@ public class TradeAfterSaleDO extends BaseDO {
132 134 private Long payRefundId;
133 135 /**
134 136 * 退款时间
135   - *
136   - * 退款成功后,才记录该时间
137 137 */
138 138 private LocalDateTime refundTime;
139 139  
... ... @@ -155,10 +155,12 @@ public class TradeAfterSaleDO extends BaseDO {
155 155 /**
156 156 * 收货时间
157 157 */
158   - private LocalDateTime receiptTime;
  158 + private LocalDateTime receiveTime;
159 159 /**
160 160 * 收货备注
  161 + *
  162 + * 注意,只有拒绝收货才会填写
161 163 */
162   - private String receiptMemo;
  164 + private String receiveReason;
163 165  
164 166 }
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderDO.java
... ... @@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.common.enums.TerminalEnum;
4 4 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
5 5 import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO.OrderItem;
6 6 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderCancelTypeEnum;
7   -import cn.iocoder.yudao.module.trade.enums.order.TradeOrderRefundStatusEnum;
  7 +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderAfterSaleStatusEnum;
8 8 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum;
9 9 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
10 10 import com.baomidou.mybatisplus.annotation.KeySequence;
... ... @@ -219,11 +219,11 @@ public class TradeOrderDO extends BaseDO {
219 219  
220 220 // ========== 退款基本信息 ==========
221 221 /**
222   - * 退款状态
  222 + * 收货状态
223 223 *
224   - * 枚举 {@link TradeOrderRefundStatusEnum}
  224 + * 枚举 {@link TradeOrderAfterSaleStatusEnum}
225 225 */
226   - private Integer refundStatus;
  226 + private Integer afterSaleStatus;
227 227 /**
228 228 * 退款金额,单位:分
229 229 *
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderItemMapper.java
... ... @@ -5,6 +5,8 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
5 5 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
6 6 import org.apache.ibatis.annotations.Mapper;
7 7  
  8 +import java.util.List;
  9 +
8 10 @Mapper
9 11 public interface TradeOrderItemMapper extends BaseMapperX<TradeOrderItemDO> {
10 12  
... ... @@ -13,4 +15,8 @@ public interface TradeOrderItemMapper extends BaseMapperX&lt;TradeOrderItemDO&gt; {
13 15 new LambdaUpdateWrapper<>(new TradeOrderItemDO().setId(id).setAfterSaleStatus(oldAfterSaleStatus)));
14 16 }
15 17  
  18 + default List<TradeOrderItemDO> selectListByOrderId(Long orderId) {
  19 + return selectList(TradeOrderItemDO::getOrderId, orderId);
  20 + }
  21 +
16 22 }
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleService.java
1 1 package cn.iocoder.yudao.module.trade.service.aftersale;
2 2  
3   -import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleAuditReqVO;
4   -import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleConfirmReqVO;
  3 +import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleDisagreeReqVO;
  4 +import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleRefuseReqVO;
5 5 import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppTradeAfterSaleCreateReqVO;
6 6 import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppTradeAfterSaleDeliveryReqVO;
7 7  
... ... @@ -13,7 +13,7 @@ import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppTradeAfterSa
13 13 public interface TradeAfterSaleService {
14 14  
15 15 /**
16   - * 创建交易售后
  16 + * 【会员】创建交易售后
17 17 * <p>
18 18 * 一般是用户发起售后请求
19 19 *
... ... @@ -24,16 +24,23 @@ public interface TradeAfterSaleService {
24 24 Long createAfterSale(Long userId, AppTradeAfterSaleCreateReqVO createReqVO);
25 25  
26 26 /**
27   - * 审批交易售后
  27 + * 【管理员】同意交易售后
  28 + *
  29 + * @param userId 管理员用户编号
  30 + * @param id 交易售后编号
  31 + */
  32 + void agreeAfterSale(Long userId, Long id);
  33 +
  34 + /**
  35 + * 【管理员】拒绝交易售后
28 36 *
29 37 * @param userId 管理员用户编号
30   - * @param userIp 操作 IP
31 38 * @param auditReqVO 审批 Request 信息
32 39 */
33   - void auditAfterSale(Long userId, String userIp, TradeAfterSaleAuditReqVO auditReqVO);
  40 + void disagreeAfterSale(Long userId, TradeAfterSaleDisagreeReqVO auditReqVO);
34 41  
35 42 /**
36   - * 退回货物
  43 + * 【会员】退回货物
37 44 *
38 45 * @param userId 会员用户编号
39 46 * @param deliveryReqVO 退货 Request 信息
... ... @@ -41,19 +48,28 @@ public interface TradeAfterSaleService {
41 48 void deliveryAfterSale(Long userId, AppTradeAfterSaleDeliveryReqVO deliveryReqVO);
42 49  
43 50 /**
44   - * 确认收货
  51 + * 【管理员】确认收货
  52 + *
  53 + * @param userId 管理员编号
  54 + * @param id 交易售后编号
  55 + */
  56 + void receiveAfterSale(Long userId, Long id);
  57 +
  58 + /**
  59 + * 【管理员】拒绝收货
45 60 *
46 61 * @param userId 管理员用户编号
47   - * @param userIp 操作 IP
48 62 * @param confirmReqVO 收货 Request 信息
49 63 */
50   - void confirmAfterSale(Long userId, String userIp, TradeAfterSaleConfirmReqVO confirmReqVO);
  64 + void refuseAfterSale(Long userId, TradeAfterSaleRefuseReqVO confirmReqVO);
51 65  
52 66 /**
53   - * 确认退款,由【pay】支付服务回调
  67 + * 【管理员】确认退款
54 68 *
55   - * @param payRefundId 支付退款编号
  69 + * @param userId 管理员用户编号
  70 + * @param userIp 管理员用户 IP
  71 + * @param id 售后编号
56 72 */
57   - void refundAfterSale(Long payRefundId);
  73 + void refundAfterSale(Long userId, String userIp, Long id);
58 74  
59 75 }
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceImpl.java
... ... @@ -4,10 +4,8 @@ import cn.hutool.core.util.ObjectUtil;
4 4 import cn.hutool.core.util.RandomUtil;
5 5 import cn.iocoder.yudao.module.pay.api.refund.PayRefundApi;
6 6 import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO;
7   -import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundRespDTO;
8   -import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum;
9   -import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleAuditReqVO;
10   -import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleConfirmReqVO;
  7 +import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleDisagreeReqVO;
  8 +import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleRefuseReqVO;
11 9 import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppTradeAfterSaleCreateReqVO;
12 10 import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppTradeAfterSaleDeliveryReqVO;
13 11 import cn.iocoder.yudao.module.trade.convert.aftersale.TradeAfterSaleConvert;
... ... @@ -28,7 +26,6 @@ import org.springframework.transaction.support.TransactionSynchronizationManager
28 26 import org.springframework.validation.annotation.Validated;
29 27  
30 28 import javax.annotation.Resource;
31   -
32 29 import java.time.LocalDateTime;
33 30  
34 31 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
... ... @@ -66,6 +63,13 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService {
66 63 return afterSale.getId();
67 64 }
68 65  
  66 + /**
  67 + * 校验交易订单项是否可以申请售后
  68 + *
  69 + * @param userId 用户编号
  70 + * @param createReqVO 售后创建信息
  71 + * @return 交易订单项
  72 + */
69 73 private TradeOrderItemDO validateOrderItemApplicable(Long userId, AppTradeAfterSaleCreateReqVO createReqVO) {
70 74 // 校验订单项存在
71 75 TradeOrderItemDO orderItem = tradeOrderService.getOrderItem(userId, createReqVO.getOrderItemId());
... ... @@ -116,7 +120,8 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService {
116 120  
117 121 // 更新交易订单项的售后状态
118 122 tradeOrderService.updateOrderItemAfterSaleStatus(tradeOrderItem.getId(),
119   - TradeOrderItemAfterSaleStatusEnum.NONE.getStatus(), TradeOrderItemAfterSaleStatusEnum.APPLY.getStatus());
  123 + TradeOrderItemAfterSaleStatusEnum.NONE.getStatus(),
  124 + TradeOrderItemAfterSaleStatusEnum.APPLY.getStatus(), null);
120 125  
121 126 // TODO 记录售后日志
122 127  
... ... @@ -125,76 +130,61 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService {
125 130 }
126 131  
127 132 @Override
128   - @Transactional
129   - public void auditAfterSale(Long userId, String userIp,
130   - TradeAfterSaleAuditReqVO auditReqVO) {
  133 + @Transactional(rollbackFor = Exception.class)
  134 + public void agreeAfterSale(Long userId, Long id) {
131 135 // 校验售后单存在,并状态未审批
132   - TradeAfterSaleDO afterSale = tradeAfterSaleMapper.selectById(auditReqVO.getId());
133   - if (afterSale == null) {
134   - throw exception(AFTER_SALE_NOT_FOUND);
135   - }
136   - if (ObjectUtil.notEqual(afterSale.getStatus(), TradeAfterSaleStatusEnum.APPLY.getStatus())) {
137   - throw exception(AFTER_SALE_AUDIT_FAIL_STATUS_NOT_APPLY);
138   - }
139   -
140   - // 进行审批
141   - if (auditReqVO.getPass()) {
142   - auditAfterSalePass(userId, userIp, auditReqVO, afterSale);
143   - } else {
144   - auditAfterSaleReject(userId, auditReqVO, afterSale);
145   - }
146   - }
  136 + TradeAfterSaleDO afterSale = validateAfterSaleAuditable(id);
147 137  
148   - private void auditAfterSalePass(Long userId, String userIp,
149   - TradeAfterSaleAuditReqVO auditReqVO, TradeAfterSaleDO afterSale) {
150 138 // 更新售后单的状态
151 139 // 情况一:退款:标记为 WAIT_REFUND 状态。后续等退款发起成功后,在标记为 COMPLETE 状态
152 140 // 情况二:退货退款:需要等用户退货后,才能发起退款
153 141 Integer newStatus = afterSale.getType().equals(TradeAfterSaleTypeEnum.REFUND.getType()) ?
154   - TradeAfterSaleStatusEnum.WAIT_REFUND.getStatus() : TradeAfterSaleStatusEnum.SELLER_PASS.getStatus();
  142 + TradeAfterSaleStatusEnum.WAIT_REFUND.getStatus() : TradeAfterSaleStatusEnum.SELLER_AGREE.getStatus();
155 143 updateAfterSaleStatus(afterSale.getId(), TradeAfterSaleStatusEnum.APPLY.getStatus(), new TradeAfterSaleDO()
156   - .setStatus(newStatus).setAuditUserId(userId)
157   - .setAuditReason(auditReqVO.getAuditReason()).setAuditTime(LocalDateTime.now()));
158   -
159   - // 如果直接退款,则发起售后退款
160   - if (afterSale.getType().equals(TradeAfterSaleTypeEnum.REFUND.getType())) {
161   - createPayRefund(userIp, afterSale);
162   - }
  144 + .setStatus(newStatus).setAuditUserId(userId).setAuditTime(LocalDateTime.now()));
163 145  
164 146 // TODO 记录售后日志
165 147  
166 148 // TODO 发送售后消息
167 149 }
168 150  
169   - private void auditAfterSaleReject(Long userId,
170   - TradeAfterSaleAuditReqVO auditReqVO, TradeAfterSaleDO afterSale) {
171   - // 更新售后单的状态
172   - Integer newStatus = TradeAfterSaleStatusEnum.SELLER_REFUSE.getStatus();
173   - updateAfterSaleStatus(afterSale.getId(), TradeAfterSaleStatusEnum.APPLY.getStatus(), new TradeAfterSaleDO()
174   - .setStatus(newStatus).setAuditUserId(userId)
175   - .setAuditReason(auditReqVO.getAuditReason()).setAuditTime(LocalDateTime.now()));
  151 + @Override
  152 + @Transactional(rollbackFor = Exception.class)
  153 + public void disagreeAfterSale(Long userId, TradeAfterSaleDisagreeReqVO auditReqVO) {
  154 + // 校验售后单存在,并状态未审批
  155 + TradeAfterSaleDO afterSale = validateAfterSaleAuditable(auditReqVO.getId());
176 156  
177   - // 更新交易订单项的售后状态为【未申请】
178   - tradeOrderService.updateOrderItemAfterSaleStatus(afterSale.getOrderItemId(),
179   - TradeOrderItemAfterSaleStatusEnum.APPLY.getStatus(), TradeOrderItemAfterSaleStatusEnum.NONE.getStatus());
  157 + // 更新售后单的状态
  158 + Integer newStatus = TradeAfterSaleStatusEnum.SELLER_DISAGREE.getStatus();
  159 + updateAfterSaleStatus(afterSale.getId(), TradeAfterSaleStatusEnum.APPLY.getStatus(), new TradeAfterSaleDO()
  160 + .setStatus(newStatus).setAuditUserId(userId).setAuditTime(LocalDateTime.now())
  161 + .setAuditReason(auditReqVO.getAuditReason()));
180 162  
181 163 // TODO 记录售后日志
182 164  
183 165 // TODO 发送售后消息
184   - }
185 166  
186   - private void createPayRefund(String userIp, TradeAfterSaleDO afterSale) {
187   - TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
  167 + // 更新交易订单项的售后状态为【未申请】
  168 + tradeOrderService.updateOrderItemAfterSaleStatus(afterSale.getOrderItemId(),
  169 + TradeOrderItemAfterSaleStatusEnum.APPLY.getStatus(),
  170 + TradeOrderItemAfterSaleStatusEnum.NONE.getStatus(), null);
  171 + }
188 172  
189   - @Override
190   - public void afterCommit() {
191   - // 创建退款单
192   - PayRefundCreateReqDTO createReqDTO = TradeAfterSaleConvert.INSTANCE.convert(userIp, afterSale, tradeOrderProperties);
193   - Long payRefundId = payRefundApi.createPayRefund(createReqDTO);
194   - // 更新售后单的退款单号
195   - tradeAfterSaleMapper.updateById(new TradeAfterSaleDO().setId(afterSale.getId()).setPayRefundId(payRefundId));
196   - }
197   - });
  173 + /**
  174 + * 校验售后单是否可审批(同意售后、拒绝售后)
  175 + *
  176 + * @param id 售后编号
  177 + * @return 售后单
  178 + */
  179 + private TradeAfterSaleDO validateAfterSaleAuditable(Long id) {
  180 + TradeAfterSaleDO afterSale = tradeAfterSaleMapper.selectById(id);
  181 + if (afterSale == null) {
  182 + throw exception(AFTER_SALE_NOT_FOUND);
  183 + }
  184 + if (ObjectUtil.notEqual(afterSale.getStatus(), TradeAfterSaleStatusEnum.APPLY.getStatus())) {
  185 + throw exception(AFTER_SALE_AUDIT_FAIL_STATUS_NOT_APPLY);
  186 + }
  187 + return afterSale;
198 188 }
199 189  
200 190 private void updateAfterSaleStatus(Long id, Integer status, TradeAfterSaleDO updateObj) {
... ... @@ -205,19 +195,20 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService {
205 195 }
206 196  
207 197 @Override
  198 + @Transactional(rollbackFor = Exception.class)
208 199 public void deliveryAfterSale(Long userId, AppTradeAfterSaleDeliveryReqVO deliveryReqVO) {
209 200 // 校验售后单存在,并状态未退货
210 201 TradeAfterSaleDO afterSale = tradeAfterSaleMapper.selectById(deliveryReqVO.getId());
211 202 if (afterSale == null) {
212 203 throw exception(AFTER_SALE_NOT_FOUND);
213 204 }
214   - if (ObjectUtil.notEqual(afterSale.getStatus(), TradeAfterSaleStatusEnum.SELLER_PASS.getStatus())) {
215   - throw exception(AFTER_SALE_DELIVERY_FAIL_STATUS_NOT_SELLER_PASS);
  205 + if (ObjectUtil.notEqual(afterSale.getStatus(), TradeAfterSaleStatusEnum.SELLER_AGREE.getStatus())) {
  206 + throw exception(AFTER_SALE_DELIVERY_FAIL_STATUS_NOT_SELLER_AGREE);
216 207 }
217 208  
218 209 // 更新售后单的物流信息
219   - updateAfterSaleStatus(afterSale.getId(), TradeAfterSaleStatusEnum.SELLER_PASS.getStatus(), new TradeAfterSaleDO()
220   - .setStatus(TradeAfterSaleStatusEnum.BUYER_RETURN.getStatus())
  210 + updateAfterSaleStatus(afterSale.getId(), TradeAfterSaleStatusEnum.SELLER_AGREE.getStatus(), new TradeAfterSaleDO()
  211 + .setStatus(TradeAfterSaleStatusEnum.BUYER_DELIVERY.getStatus())
221 212 .setLogisticsId(deliveryReqVO.getLogisticsId()).setLogisticsNo(deliveryReqVO.getLogisticsNo())
222 213 .setDeliveryTime(deliveryReqVO.getDeliveryTime()));
223 214  
... ... @@ -227,64 +218,69 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService {
227 218 }
228 219  
229 220 @Override
230   - public void confirmAfterSale(Long userId, String userIp,
231   - TradeAfterSaleConfirmReqVO confirmReqVO) {
232   - // 校验售后单存在,并状态未审批
  221 + @Transactional(rollbackFor = Exception.class)
  222 + public void receiveAfterSale(Long userId, Long id) {
  223 + // 校验售后单存在,并状态为已退货
  224 + TradeAfterSaleDO afterSale = validateAfterSaleReceivable(id);
  225 +
  226 + // 更新售后单的状态
  227 + updateAfterSaleStatus(afterSale.getId(), TradeAfterSaleStatusEnum.BUYER_DELIVERY.getStatus(), new TradeAfterSaleDO()
  228 + .setStatus(TradeAfterSaleStatusEnum.WAIT_REFUND.getStatus()).setReceiveTime(LocalDateTime.now()));
  229 +
  230 + // TODO 记录售后日志
  231 +
  232 + // TODO 发送售后消息
  233 + }
  234 +
  235 + @Override
  236 + @Transactional(rollbackFor = Exception.class)
  237 + public void refuseAfterSale(Long userId, TradeAfterSaleRefuseReqVO confirmReqVO) {
  238 + // 校验售后单存在,并状态为已退货
233 239 TradeAfterSaleDO afterSale = tradeAfterSaleMapper.selectById(confirmReqVO.getId());
234 240 if (afterSale == null) {
235 241 throw exception(AFTER_SALE_NOT_FOUND);
236 242 }
237   - if (ObjectUtil.notEqual(afterSale.getStatus(), TradeAfterSaleStatusEnum.BUYER_RETURN.getStatus())) {
238   - throw exception(AFTER_SALE_CONFIRM_FAIL_STATUS_NOT_BUYER_RETURN);
239   - }
240   -
241   - // 进行审批
242   - if (confirmReqVO.getPass()) {
243   - confirmAfterSalePass(userId, userIp, confirmReqVO, afterSale);
244   - } else {
245   - confirmAfterSaleReject(userId, confirmReqVO, afterSale);
  243 + if (ObjectUtil.notEqual(afterSale.getStatus(), TradeAfterSaleStatusEnum.BUYER_DELIVERY.getStatus())) {
  244 + throw exception(AFTER_SALE_CONFIRM_FAIL_STATUS_NOT_BUYER_DELIVERY);
246 245 }
247   - }
248 246  
249   - private void confirmAfterSalePass(Long userId, String userIp,
250   - TradeAfterSaleConfirmReqVO confirmReqVO, TradeAfterSaleDO afterSale) {
251 247 // 更新售后单的状态
252   - Integer newStatus = TradeAfterSaleStatusEnum.WAIT_REFUND.getStatus();
253   - updateAfterSaleStatus(afterSale.getId(), TradeAfterSaleStatusEnum.BUYER_RETURN.getStatus(), new TradeAfterSaleDO()
254   - .setStatus(newStatus).setReceiptTime(LocalDateTime.now()).setReceiptMemo(confirmReqVO.getReceiptMemo()));
255   -
256   - // 如果直接退款,则发起售后退款
257   - if (afterSale.getType().equals(TradeAfterSaleTypeEnum.REFUND.getType())) {
258   - createPayRefund(userIp, afterSale);
259   - }
  248 + updateAfterSaleStatus(afterSale.getId(), TradeAfterSaleStatusEnum.BUYER_DELIVERY.getStatus(), new TradeAfterSaleDO()
  249 + .setStatus(TradeAfterSaleStatusEnum.SELLER_REFUSE.getStatus()).setReceiveTime(LocalDateTime.now())
  250 + .setReceiveReason(confirmReqVO.getRefuseMemo()));
260 251  
261 252 // TODO 记录售后日志
262 253  
263 254 // TODO 发送售后消息
264   - }
265   -
266   - private void confirmAfterSaleReject(Long userId, TradeAfterSaleConfirmReqVO confirmReqVO, TradeAfterSaleDO afterSale) {
267   - // 更新售后单的状态
268   - Integer newStatus = TradeAfterSaleStatusEnum.SELLER_TERMINATION.getStatus();
269   - updateAfterSaleStatus(afterSale.getId(), TradeAfterSaleStatusEnum.BUYER_RETURN.getStatus(), new TradeAfterSaleDO()
270   - .setStatus(newStatus).setReceiptTime(LocalDateTime.now()).setReceiptMemo(confirmReqVO.getReceiptMemo()));
271 255  
272 256 // 更新交易订单项的售后状态为【未申请】
273 257 tradeOrderService.updateOrderItemAfterSaleStatus(afterSale.getOrderItemId(),
274   - TradeOrderItemAfterSaleStatusEnum.APPLY.getStatus(), TradeOrderItemAfterSaleStatusEnum.NONE.getStatus());
275   -
276   - // TODO 记录售后日志
  258 + TradeOrderItemAfterSaleStatusEnum.APPLY.getStatus(),
  259 + TradeOrderItemAfterSaleStatusEnum.NONE.getStatus(), null);
  260 + }
277 261  
278   - // TODO 发送售后消息
  262 + /**
  263 + * 校验售后单是否可收货,即处于买家已发货
  264 + *
  265 + * @param id 售后编号
  266 + * @return 售后单
  267 + */
  268 + private TradeAfterSaleDO validateAfterSaleReceivable(Long id) {
  269 + TradeAfterSaleDO afterSale = tradeAfterSaleMapper.selectById(id);
  270 + if (afterSale == null) {
  271 + throw exception(AFTER_SALE_NOT_FOUND);
  272 + }
  273 + if (ObjectUtil.notEqual(afterSale.getStatus(), TradeAfterSaleStatusEnum.BUYER_DELIVERY.getStatus())) {
  274 + throw exception(AFTER_SALE_CONFIRM_FAIL_STATUS_NOT_BUYER_DELIVERY);
  275 + }
  276 + return afterSale;
279 277 }
280 278  
281 279 @Override
282   - public void refundAfterSale(Long payRefundId) {
283   - // 校验退款单
284   - PayRefundRespDTO payRefund = validatePayRefundSuccess(payRefundId);
285   -
  280 + @Transactional(rollbackFor = Exception.class)
  281 + public void refundAfterSale(Long userId, String userIp, Long id) {
286 282 // 校验售后单的状态,并状态待退款
287   - TradeAfterSaleDO afterSale = tradeAfterSaleMapper.selectByPayRefundId(payRefundId);
  283 + TradeAfterSaleDO afterSale = tradeAfterSaleMapper.selectByPayRefundId(id);
288 284 if (afterSale == null) {
289 285 throw exception(AFTER_SALE_NOT_FOUND);
290 286 }
... ... @@ -292,28 +288,35 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService {
292 288 throw exception(AFTER_SALE_REFUND_FAIL_STATUS_NOT_WAIT_REFUND);
293 289 }
294 290  
  291 + // 发起退款单。注意,需要在事务提交后,再进行发起,避免重复发起
  292 + createPayRefund(userIp, afterSale);
  293 +
295 294 // 更新售后单的状态为【已完成】
296 295 updateAfterSaleStatus(afterSale.getId(), TradeAfterSaleStatusEnum.WAIT_REFUND.getStatus(), new TradeAfterSaleDO()
297   - .setStatus(TradeAfterSaleStatusEnum.COMPLETE.getStatus()).setRefundTime(payRefund.getSuccessTime()));
298   -
299   - // 更新交易订单项的售后状态为【已完成】
300   - tradeOrderService.updateOrderItemAfterSaleStatus(afterSale.getOrderItemId(),
301   - TradeOrderItemAfterSaleStatusEnum.APPLY.getStatus(), TradeOrderItemAfterSaleStatusEnum.SUCCESS.getStatus());
  296 + .setStatus(TradeAfterSaleStatusEnum.COMPLETE.getStatus()).setRefundTime(LocalDateTime.now()));
302 297  
303 298 // TODO 记录售后日志
304 299  
305 300 // TODO 发送售后消息
  301 +
  302 + // 更新交易订单项的售后状态为【已完成】
  303 + tradeOrderService.updateOrderItemAfterSaleStatus(afterSale.getOrderItemId(),
  304 + TradeOrderItemAfterSaleStatusEnum.APPLY.getStatus(),
  305 + TradeOrderItemAfterSaleStatusEnum.SUCCESS.getStatus(), afterSale.getRefundPrice());
306 306 }
307 307  
308   - private PayRefundRespDTO validatePayRefundSuccess(Long payRefundId) {
309   - PayRefundRespDTO payRefund = payRefundApi.getPayRefund(payRefundId);
310   - if (payRefund == null) {
311   - throw exception(AFTER_SALE_REFUND_FAIL_PAY_REFUND_NOT_FOUND);
312   - }
313   - if (PayRefundStatusEnum.isSuccess(payRefund.getStatus())) {
314   - throw exception(AFTER_SALE_REFUND_FAIL_PAY_REFUND_STATUS_NOT_SUCCESS);
315   - }
316   - return payRefund;
  308 + private void createPayRefund(String userIp, TradeAfterSaleDO afterSale) {
  309 + TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
  310 +
  311 + @Override
  312 + public void afterCommit() {
  313 + // 创建退款单
  314 + PayRefundCreateReqDTO createReqDTO = TradeAfterSaleConvert.INSTANCE.convert(userIp, afterSale, tradeOrderProperties);
  315 + Long payRefundId = payRefundApi.createPayRefund(createReqDTO);
  316 + // 更新售后单的退款单号
  317 + tradeAfterSaleMapper.updateById(new TradeAfterSaleDO().setId(afterSale.getId()).setPayRefundId(payRefundId));
  318 + }
  319 + });
317 320 }
318 321  
319 322 }
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderService.java
... ... @@ -50,6 +50,8 @@ public interface TradeOrderService {
50 50 * @param id 交易订单项编号
51 51 * @param oldAfterSaleStatus 当前售后状态;如果不符,更新后会抛出异常
52 52 * @param newAfterSaleStatus 目标售后状态
  53 + * @param refundPrice 退款金额;当订单项退款成功时,必须传递该值
53 54 */
54   - void updateOrderItemAfterSaleStatus(Long id, Integer oldAfterSaleStatus, Integer newAfterSaleStatus);
  55 + void updateOrderItemAfterSaleStatus(Long id, Integer oldAfterSaleStatus,
  56 + Integer newAfterSaleStatus, Integer refundPrice);
55 57 }
... ...
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java
... ... @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.trade.service.order;
2 2  
3 3 import cn.hutool.core.util.IdUtil;
4 4 import cn.hutool.core.util.ObjectUtil;
  5 +import cn.hutool.core.util.StrUtil;
5 6 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
6 7 import cn.iocoder.yudao.framework.common.enums.TerminalEnum;
7 8 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
... ... @@ -24,17 +25,16 @@ import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreate
24 25 import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert;
25 26 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
26 27 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
27   -import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper;
28 28 import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderItemMapper;
  29 +import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper;
29 30 import cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants;
30   -import cn.iocoder.yudao.module.trade.enums.order.TradeOrderRefundStatusEnum;
31   -import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum;
32   -import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
  31 +import cn.iocoder.yudao.module.trade.enums.order.*;
33 32 import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties;
34 33 import org.springframework.stereotype.Service;
35 34 import org.springframework.transaction.annotation.Transactional;
36 35  
37 36 import javax.annotation.Resource;
  37 +import java.time.LocalDateTime;
38 38 import java.util.List;
39 39 import java.util.Map;
40 40 import java.util.Objects;
... ... @@ -180,12 +180,12 @@ public class TradeOrderServiceImpl implements TradeOrderService {
180 180 tradeOrderDO.setNo(IdUtil.getSnowflakeNextId() + ""); // TODO @LeeYan9: 思考下, 怎么生成好点哈; 这个是会展示给用户的;
181 181 tradeOrderDO.setStatus(TradeOrderStatusEnum.UNPAID.getStatus());
182 182 tradeOrderDO.setType(TradeOrderTypeEnum.NORMAL.getType());
183   - tradeOrderDO.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus());
  183 + tradeOrderDO.setAfterSaleStatus(TradeOrderAfterSaleStatusEnum.NONE.getStatus());
184 184 tradeOrderDO.setProductCount(getSumValue(order.getItems(), PriceCalculateRespDTO.OrderItem::getCount, Integer::sum));
185 185 tradeOrderDO.setTerminal(TerminalEnum.H5.getTerminal()); // todo 数据来源?
186 186 tradeOrderDO.setAdjustPrice(0).setPayed(false); // 支付信息
187 187 tradeOrderDO.setDeliveryStatus(false); // 物流信息
188   - tradeOrderDO.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()).setRefundPrice(0); // 退款信息
  188 + tradeOrderDO.setAfterSaleStatus(TradeOrderAfterSaleStatusEnum.NONE.getStatus()).setRefundPrice(0); // 退款信息
189 189 tradeOrderMapper.insert(tradeOrderDO);
190 190 return tradeOrderDO;
191 191 }
... ... @@ -252,11 +252,52 @@ public class TradeOrderServiceImpl implements TradeOrderService {
252 252 }
253 253  
254 254 @Override
255   - public void updateOrderItemAfterSaleStatus(Long id, Integer oldAfterSaleStatus, Integer newAfterSaleStatus) {
  255 + public void updateOrderItemAfterSaleStatus(Long id, Integer oldAfterSaleStatus, Integer newAfterSaleStatus, Integer refundPrice) {
  256 + // 如果退款成功,则 refundPrice 非空
  257 + if (Objects.equals(newAfterSaleStatus, TradeOrderItemAfterSaleStatusEnum.SUCCESS.getStatus())
  258 + && refundPrice == null) {
  259 + throw new IllegalArgumentException(StrUtil.format("id({}) 退款成功,退款金额不能为空", id));
  260 + }
  261 +
  262 + // 更新订单项
256 263 int updateCount = tradeOrderItemMapper.updateAfterSaleStatus(id, oldAfterSaleStatus, newAfterSaleStatus);
257 264 if (updateCount <= 0) {
258 265 throw exception(ORDER_ITEM_UPDATE_AFTER_SALE_STATUS_FAIL);
259 266 }
  267 +
  268 + // 如果有退款金额,则需要更新订单
  269 + if (refundPrice == null) {
  270 + return;
  271 + }
  272 + // 计算总的退款金额
  273 + TradeOrderDO order = tradeOrderMapper.selectById(tradeOrderItemMapper.selectById(id).getOrderId());
  274 + Integer orderRefundPrice = order.getRefundPrice() + refundPrice;
  275 + if (isAllOrderItemAfterSaleSuccess(order.getId())) { // 如果都售后成功,则需要取消订单
  276 + tradeOrderMapper.updateById(new TradeOrderDO().setId(order.getId())
  277 + .setAfterSaleStatus(TradeOrderAfterSaleStatusEnum.ALL.getStatus()).setRefundPrice(orderRefundPrice)
  278 + .setCancelType(TradeOrderCancelTypeEnum.AFTER_SALE_CLOSE.getType()).setCancelTime(LocalDateTime.now()));
  279 +
  280 + // TODO 芋艿:记录订单日志
  281 +
  282 + // TODO 芋艿:站内信?
  283 + } else { // 如果部分售后,则更新退款金额
  284 + tradeOrderMapper.updateById(new TradeOrderDO().setId(order.getId())
  285 + .setAfterSaleStatus(TradeOrderAfterSaleStatusEnum.PART.getStatus()).setRefundPrice(orderRefundPrice));
  286 + }
  287 +
  288 + // TODO 芋艿:未来如果有分佣,需要更新相关分佣订单为已失效
  289 + }
  290 +
  291 + /**
  292 + * 判断指定订单的所有订单项,是不是都售后成功
  293 + *
  294 + * @param id 订单编号
  295 + * @return 是否都售后成功
  296 + */
  297 + private boolean isAllOrderItemAfterSaleSuccess(Long id) {
  298 + List<TradeOrderItemDO> orderItems = tradeOrderItemMapper.selectListByOrderId(id);
  299 + return orderItems.stream().allMatch(orderItem -> Objects.equals(orderItem.getAfterSaleStatus(),
  300 + TradeOrderItemAfterSaleStatusEnum.SUCCESS.getStatus()));
260 301 }
261 302  
262 303 }
... ...
yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceTest.java
... ... @@ -21,7 +21,7 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
21 21 import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper;
22 22 import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderItemMapper;
23 23 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEnum;
24   -import cn.iocoder.yudao.module.trade.enums.order.TradeOrderRefundStatusEnum;
  24 +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderAfterSaleStatusEnum;
25 25 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum;
26 26 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
27 27 import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderConfig;
... ... @@ -182,7 +182,7 @@ class TradeOrderServiceTest extends BaseDbUnitTest {
182 182 assertEquals(tradeOrderDO.getReceiverAreaId(), 3306L);
183 183 assertEquals(tradeOrderDO.getReceiverPostCode(), 85757);
184 184 assertEquals(tradeOrderDO.getReceiverDetailAddress(), "土豆村");
185   - assertEquals(tradeOrderDO.getRefundStatus(), TradeOrderRefundStatusEnum.NONE.getStatus());
  185 + assertEquals(tradeOrderDO.getAfterSaleStatus(), TradeOrderAfterSaleStatusEnum.NONE.getStatus());
186 186 assertEquals(tradeOrderDO.getRefundPrice(), 0);
187 187 assertEquals(tradeOrderDO.getCouponPrice(), 30);
188 188 assertEquals(tradeOrderDO.getPointPrice(), 10);
... ...