From cd2bc112cc4a12e0172beaa99f4ed6224d391669 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Fri, 18 Nov 2022 00:28:41 +0800 Subject: [PATCH] =?UTF-8?q?trade=EF=BC=9A=E3=80=90=E4=BA=A4=E6=98=93?= =?UTF-8?q?=E5=94=AE=E5=90=8E=E3=80=91=E5=AE=8C=E5=96=84=E5=8F=91=E8=B5=B7?= =?UTF-8?q?=E3=80=81=E5=90=8C=E6=84=8F=E3=80=81=E4=B8=8D=E5=90=8C=E6=84=8F?= =?UTF-8?q?=E3=80=81=E6=94=B6=E8=B4=A7=E3=80=81=E6=8B=92=E7=BB=9D=E6=94=B6?= =?UTF-8?q?=E8=B4=A7=E3=80=81=E9=80=80=E6=AC=BE=E7=9A=84=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../trade/enums/ErrorCodeConstants.java | 8 +- .../aftersale/TradeAfterSaleStatusEnum.java | 10 +- ...ava => TradeOrderAfterSaleStatusEnum.java} | 4 +- .../enums/order/TradeOrderCancelTypeEnum.java | 4 +- .../aftersale/TradeAfterSaleController.java | 42 ++- .../vo/TradeAfterSaleConfirmReqVO.java | 25 -- ....java => TradeAfterSaleDisagreeReqVO.java} | 13 +- .../vo/TradeAfterSaleRefuseReqVO.java | 21 ++ .../aftersale/TradeAfterSaleDO.java | 10 +- .../dal/dataobject/order/TradeOrderDO.java | 8 +- .../dal/mysql/order/TradeOrderItemMapper.java | 6 + .../aftersale/TradeAfterSaleService.java | 48 ++- .../aftersale/TradeAfterSaleServiceImpl.java | 313 +++++++++--------- .../service/order/TradeOrderService.java | 4 +- .../service/order/TradeOrderServiceImpl.java | 55 ++- .../service/order/TradeOrderServiceTest.java | 4 +- 16 files changed, 322 insertions(+), 253 deletions(-) rename yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/{TradeOrderRefundStatusEnum.java => TradeOrderAfterSaleStatusEnum.java} (83%) delete mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSaleConfirmReqVO.java rename yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/{TradeAfterSaleAuditReqVO.java => TradeAfterSaleDisagreeReqVO.java} (52%) create mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSaleRefuseReqVO.java diff --git a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java index 0a647c01b..60dd89ec0 100644 --- a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java +++ b/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 { ErrorCode AFTER_SALE_CREATE_FAIL_ORDER_ITEM_APPLIED = new ErrorCode(1011000105, "订单项已申请售后,无法重复申请"); ErrorCode AFTER_SALE_AUDIT_FAIL_STATUS_NOT_APPLY = new ErrorCode(1011000106, "审批失败,售后状态不处于审批中"); ErrorCode AFTER_SALE_UPDATE_STATUS_FAIL = new ErrorCode(1011000107, "操作售后单失败,请刷新后重试"); - ErrorCode AFTER_SALE_DELIVERY_FAIL_STATUS_NOT_SELLER_PASS = new ErrorCode(1011000108, "退货失败,售后单状态不处于【待买家退货】"); - ErrorCode AFTER_SALE_CONFIRM_FAIL_STATUS_NOT_BUYER_RETURN = new ErrorCode(1011000109, "确认收货失败,售后单状态不处于【待确认收货】"); - ErrorCode AFTER_SALE_REFUND_FAIL_PAY_REFUND_NOT_FOUND = new ErrorCode(1011000110, "退款失败,支付退款单不存在"); - ErrorCode AFTER_SALE_REFUND_FAIL_PAY_REFUND_STATUS_NOT_SUCCESS = new ErrorCode(1011000111, "退款失败,支付退款单状态不是【成功】"); - ErrorCode AFTER_SALE_REFUND_FAIL_STATUS_NOT_WAIT_REFUND = new ErrorCode(1011000112, "退款失败,售后单状态不是【待退款】"); + ErrorCode AFTER_SALE_DELIVERY_FAIL_STATUS_NOT_SELLER_AGREE = new ErrorCode(1011000108, "退货失败,售后单状态不处于【待买家退货】"); + ErrorCode AFTER_SALE_CONFIRM_FAIL_STATUS_NOT_BUYER_DELIVERY = new ErrorCode(1011000109, "确认收货失败,售后单状态不处于【待确认收货】"); + ErrorCode AFTER_SALE_REFUND_FAIL_STATUS_NOT_WAIT_REFUND = new ErrorCode(1011000110, "退款失败,售后单状态不是【待退款】"); // ========== Cart 模块 1-011-001-000 ========== ErrorCode CARD_ITEM_NOT_FOUND = new ErrorCode(1011002000, "购物车项不存在"); diff --git a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/aftersale/TradeAfterSaleStatusEnum.java b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/aftersale/TradeAfterSaleStatusEnum.java index 8d8df958c..e03520ea7 100644 --- a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/aftersale/TradeAfterSaleStatusEnum.java +++ b/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; public enum TradeAfterSaleStatusEnum { APPLY(10,"申请中"), - SELLER_PASS(20, "已通过"), // 卖家通过售后 - BUYER_RETURN(30,"待卖家收货"), // 买家退货,等待卖家收货 - WAIT_REFUND(40, "等待平台退款"), // 卖家收货,等待平台退款 + SELLER_AGREE(20, "卖家通过"), // 卖家通过售后 + BUYER_DELIVERY(30,"待卖家收货"), // 买家已退货,等待卖家收货 + WAIT_REFUND(40, "等待平台退款"), // 卖家已收货,等待平台退款 COMPLETE(50, "完成"), // 完成退款 BUYER_CANCEL(61, "买家取消售后"), - SELLER_REFUSE(62,"已拒绝"), // 卖家拒绝售后 - SELLER_TERMINATION(63,"卖家终止售后"), // 卖家拒绝收货,终止售后 + SELLER_DISAGREE(62,"卖家拒绝"), // 卖家拒绝售后 + SELLER_REFUSE(63,"卖家拒绝收货"), // 卖家拒绝收货,终止售后 ; /** diff --git a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderRefundStatusEnum.java b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderAfterSaleStatusEnum.java similarity index 83% rename from yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderRefundStatusEnum.java rename to yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderAfterSaleStatusEnum.java index 50fd88b12..d3388bfcb 100644 --- a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderRefundStatusEnum.java +++ b/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; import lombok.RequiredArgsConstructor; /** - * 交易订单 - 退款状态 + * 交易订单 - 售后状态 * * @author Sin */ @RequiredArgsConstructor @Getter -public enum TradeOrderRefundStatusEnum { +public enum TradeOrderAfterSaleStatusEnum { NONE(0, "未退款"), PART(1, "部分退款"), diff --git a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderCancelTypeEnum.java b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderCancelTypeEnum.java index 670651d4e..389fc75b0 100644 --- a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/order/TradeOrderCancelTypeEnum.java +++ b/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; public enum TradeOrderCancelTypeEnum { PAY_TIMEOUT(10, "超时未支付"), - REFUND_CLOSE(20, "退款关闭"), + AFTER_SALE_CLOSE(20, "退款关闭"), MEMBER_CANCEL(30, "买家取消"), - PAY_ON_DELIVERY(40, "已通过货到付款交易"),; + PAY_ON_DELIVERY(40, "已通过货到付款交易"),; // TODO 芋艿:这个类型,是不是可以去掉 /** * 关闭类型 diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/TradeAfterSaleController.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/TradeAfterSaleController.java index 3f94bee9a..945b19496 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/TradeAfterSaleController.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/TradeAfterSaleController.java @@ -1,8 +1,7 @@ package cn.iocoder.yudao.module.trade.controller.admin.aftersale; import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleAuditReqVO; -import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleConfirmReqVO; +import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleDisagreeReqVO; import cn.iocoder.yudao.module.trade.service.aftersale.TradeAfterSaleService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; @@ -13,7 +12,6 @@ import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; -import javax.annotation.security.PermitAll; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP; @@ -29,28 +27,38 @@ public class TradeAfterSaleController { @Resource private TradeAfterSaleService afterSaleService; - @PutMapping("/audit") - @ApiOperation("审批售后") - @PreAuthorize("@ss.hasPermission('trade:after-sale:audit')") - public CommonResult auditAfterSale(@RequestBody TradeAfterSaleAuditReqVO auditReqVO) { - afterSaleService.auditAfterSale(getLoginUserId(), getClientIP(), auditReqVO); + @PutMapping("/agree") + @ApiOperation("同意售后") + @ApiImplicitParam(name = "id", value = "售后编号", required = true, example = "1") + @PreAuthorize("@ss.hasPermission('trade:after-sale:agree')") + public CommonResult agreeAfterSale(@RequestParam("id") Long id) { + afterSaleService.agreeAfterSale(getLoginUserId(), id); return success(true); } - @PutMapping("/confirm") + @PutMapping("/disagree") + @ApiOperation("拒绝售后") + @PreAuthorize("@ss.hasPermission('trade:after-sale:disagree')") + public CommonResult disagreeAfterSale(@RequestBody TradeAfterSaleDisagreeReqVO confirmReqVO) { + afterSaleService.disagreeAfterSale(getLoginUserId(), confirmReqVO); + return success(true); + } + + @PutMapping("/receive") @ApiOperation("确认收货") - @PreAuthorize("@ss.hasPermission('trade:after-sale:audit')") - public CommonResult confirmAfterSale(@RequestBody TradeAfterSaleConfirmReqVO confirmReqVO) { - afterSaleService.confirmAfterSale(getLoginUserId(), getClientIP(), confirmReqVO); + @ApiImplicitParam(name = "id", value = "售后编号", required = true, example = "1") + @PreAuthorize("@ss.hasPermission('trade:after-sale:receive')") + public CommonResult receiveAfterSale(@RequestParam("id") Long id) { + afterSaleService.receiveAfterSale(getLoginUserId(), id); return success(true); } @PostMapping("/refund") - @ApiOperation(value = "确认退款", notes = "提供给【pay】支付服务,退款成功后进行回调") - @ApiImplicitParam(name = "payRefundId", value = "支付退款编号", required = true, example = "18888") - @PermitAll - public CommonResult refundAfterSale(@RequestParam("payRefundId") Long payRefundId) { - afterSaleService.refundAfterSale(payRefundId); + @ApiOperation(value = "确认退款") + @ApiImplicitParam(name = "id", value = "售后编号", required = true, example = "1") + @PreAuthorize("@ss.hasPermission('trade:after-sale:refund')") + public CommonResult refundAfterSale(@RequestParam("id") Long id) { + afterSaleService.refundAfterSale(getLoginUserId(), getClientIP(), id); return success(true); } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSaleConfirmReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSaleConfirmReqVO.java deleted file mode 100644 index 1c9a1fe6e..000000000 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSaleConfirmReqVO.java +++ /dev/null @@ -1,25 +0,0 @@ -package cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo; - -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; - -import javax.validation.constraints.NotNull; - -@ApiModel("管理后台 - 交易售后确认收货 Request VO") -@Data -public class TradeAfterSaleConfirmReqVO { - - @ApiModelProperty(value = "售后编号", required = true, example = "1024") - @NotNull(message = "售后编号不能为空") - private Long id; - - @ApiModelProperty(value = "收货结果", required = true, example = "true", - notes = "true - 确认收货;false - 拒绝收货") - @NotNull(message = "审批结果不能为空") - private Boolean pass; - - @ApiModelProperty(value = "收货备注", example = "你猜") - private String receiptMemo; - -} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSaleAuditReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSaleDisagreeReqVO.java similarity index 52% rename from yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSaleAuditReqVO.java rename to yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSaleDisagreeReqVO.java index 2ee605e44..67baca3b7 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSaleAuditReqVO.java +++ b/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; import io.swagger.annotations.ApiModelProperty; import lombok.Data; +import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotNull; -@ApiModel("管理后台 - 交易售后审批 Request VO") +@ApiModel("管理后台 - 交易售后拒绝 Request VO") @Data -public class TradeAfterSaleAuditReqVO { +public class TradeAfterSaleDisagreeReqVO { @ApiModelProperty(value = "售后编号", required = true, example = "1024") @NotNull(message = "售后编号不能为空") private Long id; - @ApiModelProperty(value = "审批结果", required = true, example = "true", - notes = "true - 通过;false - 不通过") - @NotNull(message = "审批结果不能为空") - private Boolean pass; - - @ApiModelProperty(value = "审批备注", example = "你猜") + @ApiModelProperty(value = "审批备注", required = true, example = "你猜") + @NotEmpty(message = "审批备注不能为空") private String auditReason; } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSaleRefuseReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSaleRefuseReqVO.java new file mode 100644 index 000000000..b74d73c7c --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSaleRefuseReqVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +@ApiModel("管理后台 - 交易售后拒绝收货 Request VO") +@Data +public class TradeAfterSaleRefuseReqVO { + + @ApiModelProperty(value = "售后编号", required = true, example = "1024") + @NotNull(message = "售后编号不能为空") + private Long id; + + @ApiModelProperty(value = "收货备注", required = true, example = "你猜") + @NotNull(message = "收货备注不能为空") + private String refuseMemo; + +} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/aftersale/TradeAfterSaleDO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/aftersale/TradeAfterSaleDO.java index ee3d48a3a..467edd0d8 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/aftersale/TradeAfterSaleDO.java +++ b/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 { private Long auditUserId; /** * 审批备注 + * + * 注意,只有审批不通过才会填写 */ private String auditReason; @@ -132,8 +134,6 @@ public class TradeAfterSaleDO extends BaseDO { private Long payRefundId; /** * 退款时间 - * - * 退款成功后,才记录该时间 */ private LocalDateTime refundTime; @@ -155,10 +155,12 @@ public class TradeAfterSaleDO extends BaseDO { /** * 收货时间 */ - private LocalDateTime receiptTime; + private LocalDateTime receiveTime; /** * 收货备注 + * + * 注意,只有拒绝收货才会填写 */ - private String receiptMemo; + private String receiveReason; } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderDO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderDO.java index 4d68799b9..fa0eb2ee6 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderDO.java +++ b/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; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO.OrderItem; import cn.iocoder.yudao.module.trade.enums.order.TradeOrderCancelTypeEnum; -import cn.iocoder.yudao.module.trade.enums.order.TradeOrderRefundStatusEnum; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderAfterSaleStatusEnum; import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum; import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; import com.baomidou.mybatisplus.annotation.KeySequence; @@ -219,11 +219,11 @@ public class TradeOrderDO extends BaseDO { // ========== 退款基本信息 ========== /** - * 退款状态 + * 收货状态 * - * 枚举 {@link TradeOrderRefundStatusEnum} + * 枚举 {@link TradeOrderAfterSaleStatusEnum} */ - private Integer refundStatus; + private Integer afterSaleStatus; /** * 退款金额,单位:分 * diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderItemMapper.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderItemMapper.java index 0db4f45b4..1eb83825f 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/order/TradeOrderItemMapper.java +++ b/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; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import org.apache.ibatis.annotations.Mapper; +import java.util.List; + @Mapper public interface TradeOrderItemMapper extends BaseMapperX { @@ -13,4 +15,8 @@ public interface TradeOrderItemMapper extends BaseMapperX { new LambdaUpdateWrapper<>(new TradeOrderItemDO().setId(id).setAfterSaleStatus(oldAfterSaleStatus))); } + default List selectListByOrderId(Long orderId) { + return selectList(TradeOrderItemDO::getOrderId, orderId); + } + } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleService.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleService.java index 0027bd43d..1eff8c94a 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleService.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleService.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.trade.service.aftersale; -import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleAuditReqVO; -import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleConfirmReqVO; +import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleDisagreeReqVO; +import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleRefuseReqVO; import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppTradeAfterSaleCreateReqVO; import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppTradeAfterSaleDeliveryReqVO; @@ -13,7 +13,7 @@ import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppTradeAfterSa public interface TradeAfterSaleService { /** - * 创建交易售后 + * 【会员】创建交易售后 *

* 一般是用户发起售后请求 * @@ -24,16 +24,23 @@ public interface TradeAfterSaleService { Long createAfterSale(Long userId, AppTradeAfterSaleCreateReqVO createReqVO); /** - * 审批交易售后 + * 【管理员】同意交易售后 * * @param userId 管理员用户编号 - * @param userIp 操作 IP - * @param auditReqVO 审批 Request 信息 + * @param id 交易售后编号 */ - void auditAfterSale(Long userId, String userIp, TradeAfterSaleAuditReqVO auditReqVO); + void agreeAfterSale(Long userId, Long id); /** - * 退回货物 + * 【管理员】拒绝交易售后 + * + * @param userId 管理员用户编号 + * @param auditReqVO 审批 Request 信息 + */ + void disagreeAfterSale(Long userId, TradeAfterSaleDisagreeReqVO auditReqVO); + + /** + * 【会员】退回货物 * * @param userId 会员用户编号 * @param deliveryReqVO 退货 Request 信息 @@ -41,19 +48,28 @@ public interface TradeAfterSaleService { void deliveryAfterSale(Long userId, AppTradeAfterSaleDeliveryReqVO deliveryReqVO); /** - * 确认收货 + * 【管理员】确认收货 * - * @param userId 管理员用户编号 - * @param userIp 操作 IP - * @param confirmReqVO 收货 Request 信息 + * @param userId 管理员编号 + * @param id 交易售后编号 */ - void confirmAfterSale(Long userId, String userIp, TradeAfterSaleConfirmReqVO confirmReqVO); + void receiveAfterSale(Long userId, Long id); /** - * 确认退款,由【pay】支付服务回调 + * 【管理员】拒绝收货 * - * @param payRefundId 支付退款编号 + * @param userId 管理员用户编号 + * @param confirmReqVO 收货 Request 信息 */ - void refundAfterSale(Long payRefundId); + void refuseAfterSale(Long userId, TradeAfterSaleRefuseReqVO confirmReqVO); + + /** + * 【管理员】确认退款 + * + * @param userId 管理员用户编号 + * @param userIp 管理员用户 IP + * @param id 售后编号 + */ + void refundAfterSale(Long userId, String userIp, Long id); } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceImpl.java index 85473513d..7db32ff2b 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceImpl.java +++ b/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; import cn.hutool.core.util.RandomUtil; import cn.iocoder.yudao.module.pay.api.refund.PayRefundApi; import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO; -import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundRespDTO; -import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum; -import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleAuditReqVO; -import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleConfirmReqVO; +import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleDisagreeReqVO; +import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleRefuseReqVO; import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppTradeAfterSaleCreateReqVO; import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppTradeAfterSaleDeliveryReqVO; import cn.iocoder.yudao.module.trade.convert.aftersale.TradeAfterSaleConvert; @@ -28,7 +26,6 @@ import org.springframework.transaction.support.TransactionSynchronizationManager import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; - import java.time.LocalDateTime; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; @@ -66,6 +63,13 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService { return afterSale.getId(); } + /** + * 校验交易订单项是否可以申请售后 + * + * @param userId 用户编号 + * @param createReqVO 售后创建信息 + * @return 交易订单项 + */ private TradeOrderItemDO validateOrderItemApplicable(Long userId, AppTradeAfterSaleCreateReqVO createReqVO) { // 校验订单项存在 TradeOrderItemDO orderItem = tradeOrderService.getOrderItem(userId, createReqVO.getOrderItemId()); @@ -116,7 +120,8 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService { // 更新交易订单项的售后状态 tradeOrderService.updateOrderItemAfterSaleStatus(tradeOrderItem.getId(), - TradeOrderItemAfterSaleStatusEnum.NONE.getStatus(), TradeOrderItemAfterSaleStatusEnum.APPLY.getStatus()); + TradeOrderItemAfterSaleStatusEnum.NONE.getStatus(), + TradeOrderItemAfterSaleStatusEnum.APPLY.getStatus(), null); // TODO 记录售后日志 @@ -125,62 +130,179 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService { } @Override - @Transactional - public void auditAfterSale(Long userId, String userIp, - TradeAfterSaleAuditReqVO auditReqVO) { + @Transactional(rollbackFor = Exception.class) + public void agreeAfterSale(Long userId, Long id) { // 校验售后单存在,并状态未审批 - TradeAfterSaleDO afterSale = tradeAfterSaleMapper.selectById(auditReqVO.getId()); + TradeAfterSaleDO afterSale = validateAfterSaleAuditable(id); + + // 更新售后单的状态 + // 情况一:退款:标记为 WAIT_REFUND 状态。后续等退款发起成功后,在标记为 COMPLETE 状态 + // 情况二:退货退款:需要等用户退货后,才能发起退款 + Integer newStatus = afterSale.getType().equals(TradeAfterSaleTypeEnum.REFUND.getType()) ? + TradeAfterSaleStatusEnum.WAIT_REFUND.getStatus() : TradeAfterSaleStatusEnum.SELLER_AGREE.getStatus(); + updateAfterSaleStatus(afterSale.getId(), TradeAfterSaleStatusEnum.APPLY.getStatus(), new TradeAfterSaleDO() + .setStatus(newStatus).setAuditUserId(userId).setAuditTime(LocalDateTime.now())); + + // TODO 记录售后日志 + + // TODO 发送售后消息 + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void disagreeAfterSale(Long userId, TradeAfterSaleDisagreeReqVO auditReqVO) { + // 校验售后单存在,并状态未审批 + TradeAfterSaleDO afterSale = validateAfterSaleAuditable(auditReqVO.getId()); + + // 更新售后单的状态 + Integer newStatus = TradeAfterSaleStatusEnum.SELLER_DISAGREE.getStatus(); + updateAfterSaleStatus(afterSale.getId(), TradeAfterSaleStatusEnum.APPLY.getStatus(), new TradeAfterSaleDO() + .setStatus(newStatus).setAuditUserId(userId).setAuditTime(LocalDateTime.now()) + .setAuditReason(auditReqVO.getAuditReason())); + + // TODO 记录售后日志 + + // TODO 发送售后消息 + + // 更新交易订单项的售后状态为【未申请】 + tradeOrderService.updateOrderItemAfterSaleStatus(afterSale.getOrderItemId(), + TradeOrderItemAfterSaleStatusEnum.APPLY.getStatus(), + TradeOrderItemAfterSaleStatusEnum.NONE.getStatus(), null); + } + + /** + * 校验售后单是否可审批(同意售后、拒绝售后) + * + * @param id 售后编号 + * @return 售后单 + */ + private TradeAfterSaleDO validateAfterSaleAuditable(Long id) { + TradeAfterSaleDO afterSale = tradeAfterSaleMapper.selectById(id); if (afterSale == null) { throw exception(AFTER_SALE_NOT_FOUND); } if (ObjectUtil.notEqual(afterSale.getStatus(), TradeAfterSaleStatusEnum.APPLY.getStatus())) { throw exception(AFTER_SALE_AUDIT_FAIL_STATUS_NOT_APPLY); } + return afterSale; + } - // 进行审批 - if (auditReqVO.getPass()) { - auditAfterSalePass(userId, userIp, auditReqVO, afterSale); - } else { - auditAfterSaleReject(userId, auditReqVO, afterSale); + private void updateAfterSaleStatus(Long id, Integer status, TradeAfterSaleDO updateObj) { + int updateCount = tradeAfterSaleMapper.updateByIdAndStatus(id, status, updateObj); + if (updateCount == 0) { + throw exception(AFTER_SALE_UPDATE_STATUS_FAIL); } } - private void auditAfterSalePass(Long userId, String userIp, - TradeAfterSaleAuditReqVO auditReqVO, TradeAfterSaleDO afterSale) { - // 更新售后单的状态 - // 情况一:退款:标记为 WAIT_REFUND 状态。后续等退款发起成功后,在标记为 COMPLETE 状态 - // 情况二:退货退款:需要等用户退货后,才能发起退款 - Integer newStatus = afterSale.getType().equals(TradeAfterSaleTypeEnum.REFUND.getType()) ? - TradeAfterSaleStatusEnum.WAIT_REFUND.getStatus() : TradeAfterSaleStatusEnum.SELLER_PASS.getStatus(); - updateAfterSaleStatus(afterSale.getId(), TradeAfterSaleStatusEnum.APPLY.getStatus(), new TradeAfterSaleDO() - .setStatus(newStatus).setAuditUserId(userId) - .setAuditReason(auditReqVO.getAuditReason()).setAuditTime(LocalDateTime.now())); - - // 如果直接退款,则发起售后退款 - if (afterSale.getType().equals(TradeAfterSaleTypeEnum.REFUND.getType())) { - createPayRefund(userIp, afterSale); + @Override + @Transactional(rollbackFor = Exception.class) + public void deliveryAfterSale(Long userId, AppTradeAfterSaleDeliveryReqVO deliveryReqVO) { + // 校验售后单存在,并状态未退货 + TradeAfterSaleDO afterSale = tradeAfterSaleMapper.selectById(deliveryReqVO.getId()); + if (afterSale == null) { + throw exception(AFTER_SALE_NOT_FOUND); } + if (ObjectUtil.notEqual(afterSale.getStatus(), TradeAfterSaleStatusEnum.SELLER_AGREE.getStatus())) { + throw exception(AFTER_SALE_DELIVERY_FAIL_STATUS_NOT_SELLER_AGREE); + } + + // 更新售后单的物流信息 + updateAfterSaleStatus(afterSale.getId(), TradeAfterSaleStatusEnum.SELLER_AGREE.getStatus(), new TradeAfterSaleDO() + .setStatus(TradeAfterSaleStatusEnum.BUYER_DELIVERY.getStatus()) + .setLogisticsId(deliveryReqVO.getLogisticsId()).setLogisticsNo(deliveryReqVO.getLogisticsNo()) + .setDeliveryTime(deliveryReqVO.getDeliveryTime())); // TODO 记录售后日志 // TODO 发送售后消息 } - private void auditAfterSaleReject(Long userId, - TradeAfterSaleAuditReqVO auditReqVO, TradeAfterSaleDO afterSale) { + @Override + @Transactional(rollbackFor = Exception.class) + public void receiveAfterSale(Long userId, Long id) { + // 校验售后单存在,并状态为已退货 + TradeAfterSaleDO afterSale = validateAfterSaleReceivable(id); + // 更新售后单的状态 - Integer newStatus = TradeAfterSaleStatusEnum.SELLER_REFUSE.getStatus(); - updateAfterSaleStatus(afterSale.getId(), TradeAfterSaleStatusEnum.APPLY.getStatus(), new TradeAfterSaleDO() - .setStatus(newStatus).setAuditUserId(userId) - .setAuditReason(auditReqVO.getAuditReason()).setAuditTime(LocalDateTime.now())); + updateAfterSaleStatus(afterSale.getId(), TradeAfterSaleStatusEnum.BUYER_DELIVERY.getStatus(), new TradeAfterSaleDO() + .setStatus(TradeAfterSaleStatusEnum.WAIT_REFUND.getStatus()).setReceiveTime(LocalDateTime.now())); + + // TODO 记录售后日志 + + // TODO 发送售后消息 + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void refuseAfterSale(Long userId, TradeAfterSaleRefuseReqVO confirmReqVO) { + // 校验售后单存在,并状态为已退货 + TradeAfterSaleDO afterSale = tradeAfterSaleMapper.selectById(confirmReqVO.getId()); + if (afterSale == null) { + throw exception(AFTER_SALE_NOT_FOUND); + } + if (ObjectUtil.notEqual(afterSale.getStatus(), TradeAfterSaleStatusEnum.BUYER_DELIVERY.getStatus())) { + throw exception(AFTER_SALE_CONFIRM_FAIL_STATUS_NOT_BUYER_DELIVERY); + } + + // 更新售后单的状态 + updateAfterSaleStatus(afterSale.getId(), TradeAfterSaleStatusEnum.BUYER_DELIVERY.getStatus(), new TradeAfterSaleDO() + .setStatus(TradeAfterSaleStatusEnum.SELLER_REFUSE.getStatus()).setReceiveTime(LocalDateTime.now()) + .setReceiveReason(confirmReqVO.getRefuseMemo())); + + // TODO 记录售后日志 + + // TODO 发送售后消息 // 更新交易订单项的售后状态为【未申请】 tradeOrderService.updateOrderItemAfterSaleStatus(afterSale.getOrderItemId(), - TradeOrderItemAfterSaleStatusEnum.APPLY.getStatus(), TradeOrderItemAfterSaleStatusEnum.NONE.getStatus()); + TradeOrderItemAfterSaleStatusEnum.APPLY.getStatus(), + TradeOrderItemAfterSaleStatusEnum.NONE.getStatus(), null); + } + + /** + * 校验售后单是否可收货,即处于买家已发货 + * + * @param id 售后编号 + * @return 售后单 + */ + private TradeAfterSaleDO validateAfterSaleReceivable(Long id) { + TradeAfterSaleDO afterSale = tradeAfterSaleMapper.selectById(id); + if (afterSale == null) { + throw exception(AFTER_SALE_NOT_FOUND); + } + if (ObjectUtil.notEqual(afterSale.getStatus(), TradeAfterSaleStatusEnum.BUYER_DELIVERY.getStatus())) { + throw exception(AFTER_SALE_CONFIRM_FAIL_STATUS_NOT_BUYER_DELIVERY); + } + return afterSale; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void refundAfterSale(Long userId, String userIp, Long id) { + // 校验售后单的状态,并状态待退款 + TradeAfterSaleDO afterSale = tradeAfterSaleMapper.selectByPayRefundId(id); + if (afterSale == null) { + throw exception(AFTER_SALE_NOT_FOUND); + } + if (ObjectUtil.notEqual(afterSale.getStatus(), TradeAfterSaleStatusEnum.WAIT_REFUND.getStatus())) { + throw exception(AFTER_SALE_REFUND_FAIL_STATUS_NOT_WAIT_REFUND); + } + + // 发起退款单。注意,需要在事务提交后,再进行发起,避免重复发起 + createPayRefund(userIp, afterSale); + + // 更新售后单的状态为【已完成】 + updateAfterSaleStatus(afterSale.getId(), TradeAfterSaleStatusEnum.WAIT_REFUND.getStatus(), new TradeAfterSaleDO() + .setStatus(TradeAfterSaleStatusEnum.COMPLETE.getStatus()).setRefundTime(LocalDateTime.now())); // TODO 记录售后日志 // TODO 发送售后消息 + + // 更新交易订单项的售后状态为【已完成】 + tradeOrderService.updateOrderItemAfterSaleStatus(afterSale.getOrderItemId(), + TradeOrderItemAfterSaleStatusEnum.APPLY.getStatus(), + TradeOrderItemAfterSaleStatusEnum.SUCCESS.getStatus(), afterSale.getRefundPrice()); } private void createPayRefund(String userIp, TradeAfterSaleDO afterSale) { @@ -197,123 +319,4 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService { }); } - private void updateAfterSaleStatus(Long id, Integer status, TradeAfterSaleDO updateObj) { - int updateCount = tradeAfterSaleMapper.updateByIdAndStatus(id, status, updateObj); - if (updateCount == 0) { - throw exception(AFTER_SALE_UPDATE_STATUS_FAIL); - } - } - - @Override - public void deliveryAfterSale(Long userId, AppTradeAfterSaleDeliveryReqVO deliveryReqVO) { - // 校验售后单存在,并状态未退货 - TradeAfterSaleDO afterSale = tradeAfterSaleMapper.selectById(deliveryReqVO.getId()); - if (afterSale == null) { - throw exception(AFTER_SALE_NOT_FOUND); - } - if (ObjectUtil.notEqual(afterSale.getStatus(), TradeAfterSaleStatusEnum.SELLER_PASS.getStatus())) { - throw exception(AFTER_SALE_DELIVERY_FAIL_STATUS_NOT_SELLER_PASS); - } - - // 更新售后单的物流信息 - updateAfterSaleStatus(afterSale.getId(), TradeAfterSaleStatusEnum.SELLER_PASS.getStatus(), new TradeAfterSaleDO() - .setStatus(TradeAfterSaleStatusEnum.BUYER_RETURN.getStatus()) - .setLogisticsId(deliveryReqVO.getLogisticsId()).setLogisticsNo(deliveryReqVO.getLogisticsNo()) - .setDeliveryTime(deliveryReqVO.getDeliveryTime())); - - // TODO 记录售后日志 - - // TODO 发送售后消息 - } - - @Override - public void confirmAfterSale(Long userId, String userIp, - TradeAfterSaleConfirmReqVO confirmReqVO) { - // 校验售后单存在,并状态未审批 - TradeAfterSaleDO afterSale = tradeAfterSaleMapper.selectById(confirmReqVO.getId()); - if (afterSale == null) { - throw exception(AFTER_SALE_NOT_FOUND); - } - if (ObjectUtil.notEqual(afterSale.getStatus(), TradeAfterSaleStatusEnum.BUYER_RETURN.getStatus())) { - throw exception(AFTER_SALE_CONFIRM_FAIL_STATUS_NOT_BUYER_RETURN); - } - - // 进行审批 - if (confirmReqVO.getPass()) { - confirmAfterSalePass(userId, userIp, confirmReqVO, afterSale); - } else { - confirmAfterSaleReject(userId, confirmReqVO, afterSale); - } - } - - private void confirmAfterSalePass(Long userId, String userIp, - TradeAfterSaleConfirmReqVO confirmReqVO, TradeAfterSaleDO afterSale) { - // 更新售后单的状态 - Integer newStatus = TradeAfterSaleStatusEnum.WAIT_REFUND.getStatus(); - updateAfterSaleStatus(afterSale.getId(), TradeAfterSaleStatusEnum.BUYER_RETURN.getStatus(), new TradeAfterSaleDO() - .setStatus(newStatus).setReceiptTime(LocalDateTime.now()).setReceiptMemo(confirmReqVO.getReceiptMemo())); - - // 如果直接退款,则发起售后退款 - if (afterSale.getType().equals(TradeAfterSaleTypeEnum.REFUND.getType())) { - createPayRefund(userIp, afterSale); - } - - // TODO 记录售后日志 - - // TODO 发送售后消息 - } - - private void confirmAfterSaleReject(Long userId, TradeAfterSaleConfirmReqVO confirmReqVO, TradeAfterSaleDO afterSale) { - // 更新售后单的状态 - Integer newStatus = TradeAfterSaleStatusEnum.SELLER_TERMINATION.getStatus(); - updateAfterSaleStatus(afterSale.getId(), TradeAfterSaleStatusEnum.BUYER_RETURN.getStatus(), new TradeAfterSaleDO() - .setStatus(newStatus).setReceiptTime(LocalDateTime.now()).setReceiptMemo(confirmReqVO.getReceiptMemo())); - - // 更新交易订单项的售后状态为【未申请】 - tradeOrderService.updateOrderItemAfterSaleStatus(afterSale.getOrderItemId(), - TradeOrderItemAfterSaleStatusEnum.APPLY.getStatus(), TradeOrderItemAfterSaleStatusEnum.NONE.getStatus()); - - // TODO 记录售后日志 - - // TODO 发送售后消息 - } - - @Override - public void refundAfterSale(Long payRefundId) { - // 校验退款单 - PayRefundRespDTO payRefund = validatePayRefundSuccess(payRefundId); - - // 校验售后单的状态,并状态待退款 - TradeAfterSaleDO afterSale = tradeAfterSaleMapper.selectByPayRefundId(payRefundId); - if (afterSale == null) { - throw exception(AFTER_SALE_NOT_FOUND); - } - if (ObjectUtil.notEqual(afterSale.getStatus(), TradeAfterSaleStatusEnum.WAIT_REFUND.getStatus())) { - throw exception(AFTER_SALE_REFUND_FAIL_STATUS_NOT_WAIT_REFUND); - } - - // 更新售后单的状态为【已完成】 - updateAfterSaleStatus(afterSale.getId(), TradeAfterSaleStatusEnum.WAIT_REFUND.getStatus(), new TradeAfterSaleDO() - .setStatus(TradeAfterSaleStatusEnum.COMPLETE.getStatus()).setRefundTime(payRefund.getSuccessTime())); - - // 更新交易订单项的售后状态为【已完成】 - tradeOrderService.updateOrderItemAfterSaleStatus(afterSale.getOrderItemId(), - TradeOrderItemAfterSaleStatusEnum.APPLY.getStatus(), TradeOrderItemAfterSaleStatusEnum.SUCCESS.getStatus()); - - // TODO 记录售后日志 - - // TODO 发送售后消息 - } - - private PayRefundRespDTO validatePayRefundSuccess(Long payRefundId) { - PayRefundRespDTO payRefund = payRefundApi.getPayRefund(payRefundId); - if (payRefund == null) { - throw exception(AFTER_SALE_REFUND_FAIL_PAY_REFUND_NOT_FOUND); - } - if (PayRefundStatusEnum.isSuccess(payRefund.getStatus())) { - throw exception(AFTER_SALE_REFUND_FAIL_PAY_REFUND_STATUS_NOT_SUCCESS); - } - return payRefund; - } - } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderService.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderService.java index 6a529decb..be101bbe6 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderService.java +++ b/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 { * @param id 交易订单项编号 * @param oldAfterSaleStatus 当前售后状态;如果不符,更新后会抛出异常 * @param newAfterSaleStatus 目标售后状态 + * @param refundPrice 退款金额;当订单项退款成功时,必须传递该值 */ - void updateOrderItemAfterSaleStatus(Long id, Integer oldAfterSaleStatus, Integer newAfterSaleStatus); + void updateOrderItemAfterSaleStatus(Long id, Integer oldAfterSaleStatus, + Integer newAfterSaleStatus, Integer refundPrice); } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java index 40e8a0eac..912c5116e 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java +++ b/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; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.enums.TerminalEnum; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; @@ -24,17 +25,16 @@ import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreate import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert; import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; -import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper; import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderItemMapper; +import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper; import cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants; -import cn.iocoder.yudao.module.trade.enums.order.TradeOrderRefundStatusEnum; -import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum; -import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; +import cn.iocoder.yudao.module.trade.enums.order.*; import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; +import java.time.LocalDateTime; import java.util.List; import java.util.Map; import java.util.Objects; @@ -180,12 +180,12 @@ public class TradeOrderServiceImpl implements TradeOrderService { tradeOrderDO.setNo(IdUtil.getSnowflakeNextId() + ""); // TODO @LeeYan9: 思考下, 怎么生成好点哈; 这个是会展示给用户的; tradeOrderDO.setStatus(TradeOrderStatusEnum.UNPAID.getStatus()); tradeOrderDO.setType(TradeOrderTypeEnum.NORMAL.getType()); - tradeOrderDO.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()); + tradeOrderDO.setAfterSaleStatus(TradeOrderAfterSaleStatusEnum.NONE.getStatus()); tradeOrderDO.setProductCount(getSumValue(order.getItems(), PriceCalculateRespDTO.OrderItem::getCount, Integer::sum)); tradeOrderDO.setTerminal(TerminalEnum.H5.getTerminal()); // todo 数据来源? tradeOrderDO.setAdjustPrice(0).setPayed(false); // 支付信息 tradeOrderDO.setDeliveryStatus(false); // 物流信息 - tradeOrderDO.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()).setRefundPrice(0); // 退款信息 + tradeOrderDO.setAfterSaleStatus(TradeOrderAfterSaleStatusEnum.NONE.getStatus()).setRefundPrice(0); // 退款信息 tradeOrderMapper.insert(tradeOrderDO); return tradeOrderDO; } @@ -252,11 +252,52 @@ public class TradeOrderServiceImpl implements TradeOrderService { } @Override - public void updateOrderItemAfterSaleStatus(Long id, Integer oldAfterSaleStatus, Integer newAfterSaleStatus) { + public void updateOrderItemAfterSaleStatus(Long id, Integer oldAfterSaleStatus, Integer newAfterSaleStatus, Integer refundPrice) { + // 如果退款成功,则 refundPrice 非空 + if (Objects.equals(newAfterSaleStatus, TradeOrderItemAfterSaleStatusEnum.SUCCESS.getStatus()) + && refundPrice == null) { + throw new IllegalArgumentException(StrUtil.format("id({}) 退款成功,退款金额不能为空", id)); + } + + // 更新订单项 int updateCount = tradeOrderItemMapper.updateAfterSaleStatus(id, oldAfterSaleStatus, newAfterSaleStatus); if (updateCount <= 0) { throw exception(ORDER_ITEM_UPDATE_AFTER_SALE_STATUS_FAIL); } + + // 如果有退款金额,则需要更新订单 + if (refundPrice == null) { + return; + } + // 计算总的退款金额 + TradeOrderDO order = tradeOrderMapper.selectById(tradeOrderItemMapper.selectById(id).getOrderId()); + Integer orderRefundPrice = order.getRefundPrice() + refundPrice; + if (isAllOrderItemAfterSaleSuccess(order.getId())) { // 如果都售后成功,则需要取消订单 + tradeOrderMapper.updateById(new TradeOrderDO().setId(order.getId()) + .setAfterSaleStatus(TradeOrderAfterSaleStatusEnum.ALL.getStatus()).setRefundPrice(orderRefundPrice) + .setCancelType(TradeOrderCancelTypeEnum.AFTER_SALE_CLOSE.getType()).setCancelTime(LocalDateTime.now())); + + // TODO 芋艿:记录订单日志 + + // TODO 芋艿:站内信? + } else { // 如果部分售后,则更新退款金额 + tradeOrderMapper.updateById(new TradeOrderDO().setId(order.getId()) + .setAfterSaleStatus(TradeOrderAfterSaleStatusEnum.PART.getStatus()).setRefundPrice(orderRefundPrice)); + } + + // TODO 芋艿:未来如果有分佣,需要更新相关分佣订单为已失效 + } + + /** + * 判断指定订单的所有订单项,是不是都售后成功 + * + * @param id 订单编号 + * @return 是否都售后成功 + */ + private boolean isAllOrderItemAfterSaleSuccess(Long id) { + List orderItems = tradeOrderItemMapper.selectListByOrderId(id); + return orderItems.stream().allMatch(orderItem -> Objects.equals(orderItem.getAfterSaleStatus(), + TradeOrderItemAfterSaleStatusEnum.SUCCESS.getStatus())); } } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceTest.java b/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceTest.java index 13e33d85f..66e494b1c 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceTest.java +++ b/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; import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper; import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderItemMapper; import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEnum; -import cn.iocoder.yudao.module.trade.enums.order.TradeOrderRefundStatusEnum; +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderAfterSaleStatusEnum; import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum; import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderConfig; @@ -182,7 +182,7 @@ class TradeOrderServiceTest extends BaseDbUnitTest { assertEquals(tradeOrderDO.getReceiverAreaId(), 3306L); assertEquals(tradeOrderDO.getReceiverPostCode(), 85757); assertEquals(tradeOrderDO.getReceiverDetailAddress(), "土豆村"); - assertEquals(tradeOrderDO.getRefundStatus(), TradeOrderRefundStatusEnum.NONE.getStatus()); + assertEquals(tradeOrderDO.getAfterSaleStatus(), TradeOrderAfterSaleStatusEnum.NONE.getStatus()); assertEquals(tradeOrderDO.getRefundPrice(), 0); assertEquals(tradeOrderDO.getCouponPrice(), 30); assertEquals(tradeOrderDO.getPointPrice(), 10);