From 92dbf093ead8fee50abab79f32e8d6faf406246a Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 16 Nov 2022 22:17:07 +0800 Subject: [PATCH] =?UTF-8?q?trade=EF=BC=9A=E5=A2=9E=E5=8A=A0=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E5=91=98=E5=AE=A1=E6=89=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../trade/enums/ErrorCodeConstants.java | 4 +- .../aftersale/TradeAfterSaleController.java | 40 +++++++ .../vo/TradeAfterSaleAuditReqVO.java | 25 ++++ ....java => AppTradeAfterSaleController.java} | 6 +- ...java => AppTradeAfterSaleCreateReqVO.java} | 2 +- .../aftersale/TradeAfterSaleConvert.java | 14 ++- .../convert/order/TradeOrderConvert.java | 8 +- .../mysql/aftersale/TradeAfterSaleMapper.java | 8 +- .../dal/mysql/order/TradeOrderItemMapper.java | 7 ++ .../aftersale/TradeAfterSaleService.java | 17 ++- .../aftersale/TradeAfterSaleServiceImpl.java | 112 +++++++++++++++++- .../service/order/TradeOrderService.java | 24 +++- .../service/order/TradeOrderServiceImpl.java | 39 +++--- .../module/pay/api/order/PayOrderApi.java | 4 +- .../PayOrderCreateReqDTO.java} | 4 +- .../module/pay/api/refund/PayRefundApi.java | 22 ++++ .../api/refund/dto/PayRefundCreateReqDTO.java | 52 ++++++++ .../yudao/module/pay/api/PayOrderApiImpl.java | 18 --- .../module/pay/api/order/PayOrderApiImpl.java | 36 +++--- .../pay/api/refund/PayRefundApiImpl.java | 21 ++++ 20 files changed, 381 insertions(+), 82 deletions(-) create mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/TradeAfterSaleController.java create mode 100644 yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSaleAuditReqVO.java rename yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/{AppAfterSaleController.java => AppTradeAfterSaleController.java} (87%) rename yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/vo/{AppAfterSaleCreateReqVO.java => AppTradeAfterSaleCreateReqVO.java} (97%) rename yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/{PayOrderInfoCreateReqDTO.java => dto/PayOrderCreateReqDTO.java} (93%) create mode 100644 yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/refund/PayRefundApi.java create mode 100644 yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/refund/dto/PayRefundCreateReqDTO.java delete mode 100644 yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/PayOrderApiImpl.java create mode 100644 yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/refund/PayRefundApiImpl.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 7d31d3cb7..1dfe17472 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 @@ -21,6 +21,7 @@ public interface ErrorCodeConstants { ErrorCode ORDER_ITEM_NOT_FOUND = new ErrorCode(1011000010, "交易订单项不存在"); ErrorCode ORDER_NOT_FOUND = new ErrorCode(1011000010, "交易订单不存在"); + ErrorCode ORDER_ITEM_UPDATE_AFTER_SALE_STATUS_FAIL = new ErrorCode(1011000011, "交易订单项更新售后状态失败,请重试"); // ========== After Sale 模块 1-011-000-000 ========== ErrorCode AFTER_SALE_NOT_FOUND = new ErrorCode(1011000100, "售后单不存在"); @@ -29,9 +30,10 @@ public interface ErrorCodeConstants { ErrorCode AFTER_SALE_CREATE_FAIL_ORDER_STATUS_NO_PAID = new ErrorCode(1011000103, "订单未支付,无法申请售后"); ErrorCode AFTER_SALE_CREATE_FAIL_ORDER_STATUS_NO_DELIVERED = new ErrorCode(1011000104, "订单未发货,无法申请【退货退款】售后"); 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(1011000106, "操作售后单失败,请刷新后重试"); // ========== Cart 模块 1-011-001-000 ========== ErrorCode CARD_ITEM_NOT_FOUND = new ErrorCode(1011002000, "购物车项不存在"); - } 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 new file mode 100644 index 000000000..9a6311860 --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/TradeAfterSaleController.java @@ -0,0 +1,40 @@ +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.service.aftersale.TradeAfterSaleService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + +@Api(tags = "管理后台 - 交易售后") +@RestController +@RequestMapping("/trade/after-sale") +@Validated +@Slf4j +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); + 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/TradeAfterSaleAuditReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSaleAuditReqVO.java new file mode 100644 index 000000000..1df9a383a --- /dev/null +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/TradeAfterSaleAuditReqVO.java @@ -0,0 +1,25 @@ +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 TradeAfterSaleAuditReqVO { + + @ApiModelProperty(value = "售后编号", required = true, example = "1024") + @NotNull(message = "售后编号不能为空") + private Long id; + + @ApiModelProperty(value = "审批结果", required = true, example = "true", + notes = "true - 通过;false - 不通过") + @NotNull(message = "审批结果不能为空") + private Boolean audit; + + @ApiModelProperty(value = "审批备注", example = "你猜") + private String auditReason; + +} diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/AppAfterSaleController.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/AppTradeAfterSaleController.java similarity index 87% rename from yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/AppAfterSaleController.java rename to yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/AppTradeAfterSaleController.java index 789b6e52a..23fd8fcf8 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/AppAfterSaleController.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/AppTradeAfterSaleController.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.trade.controller.app.aftersale; import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSaleCreateReqVO; +import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppTradeAfterSaleCreateReqVO; import cn.iocoder.yudao.module.trade.service.aftersale.TradeAfterSaleService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; @@ -22,14 +22,14 @@ import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUti @RequestMapping("/trade/after-sale") @Validated @Slf4j -public class AppAfterSaleController { +public class AppTradeAfterSaleController { @Resource private TradeAfterSaleService afterSaleService; @PostMapping(value = "/create") @ApiOperation(value = "申请售后") - private CommonResult createAfterSale(@RequestBody AppAfterSaleCreateReqVO createReqVO) { + private CommonResult createAfterSale(@RequestBody AppTradeAfterSaleCreateReqVO createReqVO) { return success(afterSaleService.createAfterSale(getLoginUserId(), createReqVO)); } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/vo/AppAfterSaleCreateReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/vo/AppTradeAfterSaleCreateReqVO.java similarity index 97% rename from yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/vo/AppAfterSaleCreateReqVO.java rename to yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/vo/AppTradeAfterSaleCreateReqVO.java index eceba596b..32ae40614 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/vo/AppAfterSaleCreateReqVO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/aftersale/vo/AppTradeAfterSaleCreateReqVO.java @@ -12,7 +12,7 @@ import java.util.List; @ApiModel("用户 App - 交易售后创建 Request VO") @Data -public class AppAfterSaleCreateReqVO { +public class AppTradeAfterSaleCreateReqVO { @ApiModelProperty(name = "订单项编号", required = true, example = "1024") @NotNull(message = "订单项编号不能为空") diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/aftersale/TradeAfterSaleConvert.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/aftersale/TradeAfterSaleConvert.java index 8354c1fec..afe918d2c 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/aftersale/TradeAfterSaleConvert.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/aftersale/TradeAfterSaleConvert.java @@ -1,8 +1,10 @@ package cn.iocoder.yudao.module.trade.convert.aftersale; -import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSaleCreateReqVO; +import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO; +import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppTradeAfterSaleCreateReqVO; import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.TradeAfterSaleDO; import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; +import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties; import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.Mappings; @@ -20,6 +22,14 @@ public interface TradeAfterSaleConvert { @Mapping(target = "creator", ignore = true), @Mapping(target = "updater", ignore = true), }) - TradeAfterSaleDO convert(AppAfterSaleCreateReqVO createReqVO, TradeOrderItemDO tradeOrderItem); + TradeAfterSaleDO convert(AppTradeAfterSaleCreateReqVO createReqVO, TradeOrderItemDO tradeOrderItem); + + @Mappings({ + @Mapping(source = "afterSale.orderId", target = "merchantOrderId"), + @Mapping(source = "afterSale.applyReason", target = "reason"), + @Mapping(source = "afterSale.refundPrice", target = "amount") + }) + PayRefundCreateReqDTO convert(String userIp, TradeAfterSaleDO afterSale, + TradeOrderProperties orderProperties); } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java index 4e2b747ff..c67e0e16d 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java @@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.trade.convert.order; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO; -import cn.iocoder.yudao.module.pay.api.order.PayOrderInfoCreateReqDTO; +import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO; import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO; import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; @@ -71,9 +71,9 @@ public interface TradeOrderConvert { ProductSkuUpdateStockReqDTO.Item convert(TradeOrderItemDO bean); List convertList(List list); - default PayOrderInfoCreateReqDTO convert(TradeOrderDO tradeOrderDO, List tradeOrderItemDOs, - List spus, TradeOrderProperties tradeOrderProperties) { - PayOrderInfoCreateReqDTO createReqDTO = new PayOrderInfoCreateReqDTO() + default PayOrderCreateReqDTO convert(TradeOrderDO tradeOrderDO, List tradeOrderItemDOs, + List spus, TradeOrderProperties tradeOrderProperties) { + PayOrderCreateReqDTO createReqDTO = new PayOrderCreateReqDTO() .setAppId(tradeOrderProperties.getAppId()).setUserIp(tradeOrderDO.getUserIp()); // 商户相关字段 createReqDTO.setMerchantOrderId(String.valueOf(tradeOrderDO.getId())); diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/aftersale/TradeAfterSaleMapper.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/aftersale/TradeAfterSaleMapper.java index af729e80c..b391c4b85 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/aftersale/TradeAfterSaleMapper.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/aftersale/TradeAfterSaleMapper.java @@ -2,9 +2,15 @@ package cn.iocoder.yudao.module.trade.dal.mysql.aftersale; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.TradeAfterSaleDO; -import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import org.apache.ibatis.annotations.Mapper; @Mapper public interface TradeAfterSaleMapper extends BaseMapperX { + + default int updateByIdAndStatus(Long id, Integer status, TradeAfterSaleDO update) { + return update(update, new LambdaUpdateWrapper() + .eq(TradeAfterSaleDO::getId, id).eq(TradeAfterSaleDO::getStatus, status)); + } + } 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 6565c7310..0db4f45b4 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 @@ -2,8 +2,15 @@ package cn.iocoder.yudao.module.trade.dal.mysql.order; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import org.apache.ibatis.annotations.Mapper; @Mapper public interface TradeOrderItemMapper extends BaseMapperX { + + default int updateAfterSaleStatus(Long id, Integer oldAfterSaleStatus, Integer newAfterSaleStatus) { + return update(new TradeOrderItemDO().setAfterSaleStatus(newAfterSaleStatus), + new LambdaUpdateWrapper<>(new TradeOrderItemDO().setId(id).setAfterSaleStatus(oldAfterSaleStatus))); + } + } 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 1e3c55be1..ec9e579bf 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,6 +1,7 @@ package cn.iocoder.yudao.module.trade.service.aftersale; -import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSaleCreateReqVO; +import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleAuditReqVO; +import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppTradeAfterSaleCreateReqVO; /** * 交易售后 Service 接口 @@ -14,10 +15,18 @@ public interface TradeAfterSaleService { *

* 一般是用户发起售后请求 * - * @param userId 用户编号 - * @param createReqVO 交易售后 Request 信息 + * @param userId 会员用户编号 + * @param createReqVO 创建 Request 信息 * @return 交易售后编号 */ - Long createAfterSale(Long userId, AppAfterSaleCreateReqVO createReqVO); + Long createAfterSale(Long userId, AppTradeAfterSaleCreateReqVO createReqVO); + /** + * 审批交易售后 + * + * @param userId 管理员用户编号 + * @param userIp 操作 IP + * @param auditReqVO 审批 Request 信息 + */ + void auditAfterSale(Long userId, String userIp, TradeAfterSaleAuditReqVO auditReqVO); } 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 3bfd8f7f8..7e7ee6a80 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 @@ -1,7 +1,10 @@ package cn.iocoder.yudao.module.trade.service.aftersale; import cn.hutool.core.util.RandomUtil; -import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppAfterSaleCreateReqVO; +import cn.iocoder.yudao.module.pay.api.refund.PayRefundApi; +import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO; +import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleAuditReqVO; +import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppTradeAfterSaleCreateReqVO; import cn.iocoder.yudao.module.trade.convert.aftersale.TradeAfterSaleConvert; import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.TradeAfterSaleDO; import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; @@ -11,12 +14,18 @@ import cn.iocoder.yudao.module.trade.enums.aftersale.TradeAfterSaleStatusEnum; import cn.iocoder.yudao.module.trade.enums.aftersale.TradeAfterSaleTypeEnum; import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEnum; import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum; +import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties; import cn.iocoder.yudao.module.trade.service.order.TradeOrderService; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.transaction.support.TransactionSynchronization; +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; import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*; @@ -35,8 +44,15 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService { @Resource private TradeAfterSaleMapper tradeAfterSaleMapper; + @Resource + private PayRefundApi payRefundApi; + + @Resource + private TradeOrderProperties tradeOrderProperties; + @Override - public Long createAfterSale(Long userId, AppAfterSaleCreateReqVO createReqVO) { + @Transactional(rollbackFor = Exception.class) + public Long createAfterSale(Long userId, AppTradeAfterSaleCreateReqVO createReqVO) { // 第一步,前置校验 TradeOrderItemDO tradeOrderItem = validateOrderItemApplicable(userId, createReqVO); @@ -45,7 +61,7 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService { return afterSale.getId(); } - private TradeOrderItemDO validateOrderItemApplicable(Long userId, AppAfterSaleCreateReqVO createReqVO) { + private TradeOrderItemDO validateOrderItemApplicable(Long userId, AppTradeAfterSaleCreateReqVO createReqVO) { // 校验订单项存在 TradeOrderItemDO orderItem = tradeOrderService.getOrderItem(userId, createReqVO.getOrderItemId()); if (orderItem == null) { @@ -84,7 +100,7 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService { return orderItem; } - private TradeAfterSaleDO createAfterSale(AppAfterSaleCreateReqVO createReqVO, + private TradeAfterSaleDO createAfterSale(AppTradeAfterSaleCreateReqVO createReqVO, TradeOrderItemDO tradeOrderItem) { // 创建售后单 TradeAfterSaleDO afterSale = TradeAfterSaleConvert.INSTANCE.convert(createReqVO, tradeOrderItem); @@ -93,10 +109,94 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService { // TODO 退还积分 tradeAfterSaleMapper.insert(afterSale); - // 更新交易订单项的售后状态 TODO + // 更新交易订单项的售后状态 + tradeOrderService.updateOrderItemAfterSaleStatus(tradeOrderItem.getId(), + TradeOrderItemAfterSaleStatusEnum.NONE.getStatus(), TradeOrderItemAfterSaleStatusEnum.APPLY.getStatus()); - // 发送售后消息 + // TODO 记录售后日志 + + // TODO 发送售后消息 return afterSale; } + @Override + @Transactional + public void auditAfterSale(Long userId, String userIp, + TradeAfterSaleAuditReqVO auditReqVO) { + // 校验售后单存在,并状态未审批 + TradeAfterSaleDO afterSale = tradeAfterSaleMapper.selectById(auditReqVO.getId()); + if (afterSale == null) { + throw exception(AFTER_SALE_NOT_FOUND); + } + if (afterSale.getStatus().equals(TradeAfterSaleStatusEnum.APPLY.getStatus())) { + throw exception(AFTER_SALE_AUDIT_FAIL_STATUS_NOT_APPLY); + } + + // 进行审批 + if (auditReqVO.getAudit()) { + auditAfterSalePass(userId, userIp, auditReqVO, afterSale); + } else { + auditAfterSaleReject(userId, auditReqVO, afterSale); + } + } + + 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); + } + + // TODO 记录售后日志 + + // TODO 发送售后消息 + } + + private void auditAfterSaleReject(Long userId, + TradeAfterSaleAuditReqVO auditReqVO, TradeAfterSaleDO afterSale) { + // 更新售后单的状态 + Integer newStatus = TradeAfterSaleStatusEnum.SELLER_REFUSE.getStatus(); + updateAfterSaleStatus(afterSale.getId(), TradeAfterSaleStatusEnum.APPLY.getStatus(), new TradeAfterSaleDO() + .setStatus(newStatus).setAuditUserId(userId) + .setAuditReason(auditReqVO.getAuditReason()).setAuditTime(LocalDateTime.now())); + + // 更新交易订单项的售后状态为【未申请】 + tradeOrderService.updateOrderItemAfterSaleStatus(afterSale.getOrderItemId(), + TradeOrderItemAfterSaleStatusEnum.APPLY.getStatus(), TradeOrderItemAfterSaleStatusEnum.NONE.getStatus()); + + // TODO 记录售后日志 + + // TODO 发送售后消息 + } + + private void createPayRefund(String userIp, TradeAfterSaleDO afterSale) { + TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { + + @Override + public void afterCommit() { + // 创建退款单 + PayRefundCreateReqDTO createReqDTO = TradeAfterSaleConvert.INSTANCE.convert(userIp, afterSale, tradeOrderProperties); + Long payRefundId = payRefundApi.createPayRefund(createReqDTO); + // 更新售后单的退款单号 + tradeAfterSaleMapper.updateById(new TradeAfterSaleDO().setId(afterSale.getId()).setPayRefundId(payRefundId)); + } + }); + } + + 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); + } + } + } 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 f6f012da4..6a529decb 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 @@ -12,6 +12,8 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; */ public interface TradeOrderService { + // =================== Order =================== + /** * 创建交易订单 * @@ -22,6 +24,17 @@ public interface TradeOrderService { */ Long createOrder(Long userId, String userIp, AppTradeOrderCreateReqVO createReqVO); + /** + * 获得指定用户,指定的交易订单 + * + * @param userId 用户编号 + * @param orderId 交易订单编号 + * @return 交易订单 + */ + TradeOrderDO getOrder(Long userId, Long orderId); + + // =================== Order Item =================== + /** * 获得指定用户,指定的交易订单项 * @@ -32,12 +45,11 @@ public interface TradeOrderService { TradeOrderItemDO getOrderItem(Long userId, Long itemId); /** - * 获得指定用户,指定的交易订单 + * 更新交易订单项的售后状态 * - * @param userId 用户编号 - * @param orderId 交易订单编号 - * @return 交易订单 + * @param id 交易订单项编号 + * @param oldAfterSaleStatus 当前售后状态;如果不符,更新后会抛出异常 + * @param newAfterSaleStatus 目标售后状态 */ - TradeOrderDO getOrder(Long userId, Long orderId); - + void updateOrderItemAfterSaleStatus(Long id, Integer oldAfterSaleStatus, Integer newAfterSaleStatus); } 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 1a737a9ef..40e8a0eac 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 @@ -8,7 +8,7 @@ import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.module.member.api.address.AddressApi; import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO; import cn.iocoder.yudao.module.pay.api.order.PayOrderApi; -import cn.iocoder.yudao.module.pay.api.order.PayOrderInfoCreateReqDTO; +import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO; import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO; @@ -42,8 +42,7 @@ import java.util.Set; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; -import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.ORDER_CREATE_SKU_NOT_SALE; -import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.ORDER_CREATE_SPU_NOT_FOUND; +import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*; /** * 交易订单 Service 实现类 @@ -75,6 +74,8 @@ public class TradeOrderServiceImpl implements TradeOrderService { @Resource private TradeOrderProperties tradeOrderProperties; + // =================== Order =================== + @Override @Transactional(rollbackFor = Exception.class) public Long createOrder(Long userId, String userIp, AppTradeOrderCreateReqVO createReqVO) { @@ -99,16 +100,6 @@ public class TradeOrderServiceImpl implements TradeOrderService { return tradeOrderDO.getId(); } - @Override - public TradeOrderItemDO getOrderItem(Long userId, Long itemId) { - TradeOrderItemDO orderItem = tradeOrderItemMapper.selectById(itemId); - if (orderItem != null - && ObjectUtil.notEqual(orderItem.getUserId(), userId)) { - return null; - } - return orderItem; - } - @Override public TradeOrderDO getOrder(Long userId, Long orderId) { TradeOrderDO order = tradeOrderMapper.selectById(orderId); @@ -240,7 +231,7 @@ public class TradeOrderServiceImpl implements TradeOrderService { private void createPayOrder(TradeOrderDO tradeOrderDO, List tradeOrderItemDOs, List spus) { // 创建支付单,用于后续的支付 - PayOrderInfoCreateReqDTO payOrderCreateReqDTO = TradeOrderConvert.INSTANCE.convert( + PayOrderCreateReqDTO payOrderCreateReqDTO = TradeOrderConvert.INSTANCE.convert( tradeOrderDO, tradeOrderItemDOs, spus, tradeOrderProperties); Long payOrderId = payOrderApi.createPayOrder(payOrderCreateReqDTO); @@ -248,4 +239,24 @@ public class TradeOrderServiceImpl implements TradeOrderService { tradeOrderMapper.updateById(new TradeOrderDO().setId(tradeOrderDO.getId()).setPayOrderId(payOrderId)); } + // =================== Order =================== + + @Override + public TradeOrderItemDO getOrderItem(Long userId, Long itemId) { + TradeOrderItemDO orderItem = tradeOrderItemMapper.selectById(itemId); + if (orderItem != null + && ObjectUtil.notEqual(orderItem.getUserId(), userId)) { + return null; + } + return orderItem; + } + + @Override + public void updateOrderItemAfterSaleStatus(Long id, Integer oldAfterSaleStatus, Integer newAfterSaleStatus) { + int updateCount = tradeOrderItemMapper.updateAfterSaleStatus(id, oldAfterSaleStatus, newAfterSaleStatus); + if (updateCount <= 0) { + throw exception(ORDER_ITEM_UPDATE_AFTER_SALE_STATUS_FAIL); + } + } + } diff --git a/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderApi.java b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderApi.java index 36022b172..f6cf7be30 100644 --- a/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderApi.java +++ b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderApi.java @@ -1,5 +1,7 @@ package cn.iocoder.yudao.module.pay.api.order; +import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO; + import javax.validation.Valid; /** @@ -16,6 +18,6 @@ public interface PayOrderApi { * @param reqDTO 创建请求 * @return 支付单编号 */ - Long createPayOrder(@Valid PayOrderInfoCreateReqDTO reqDTO); + Long createPayOrder(@Valid PayOrderCreateReqDTO reqDTO); } diff --git a/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderInfoCreateReqDTO.java b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/dto/PayOrderCreateReqDTO.java similarity index 93% rename from yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderInfoCreateReqDTO.java rename to yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/dto/PayOrderCreateReqDTO.java index b5f64478d..88f0342af 100644 --- a/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderInfoCreateReqDTO.java +++ b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/dto/PayOrderCreateReqDTO.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.pay.api.order; +package cn.iocoder.yudao.module.pay.api.order.dto; import lombok.Data; import org.hibernate.validator.constraints.Length; @@ -15,7 +15,7 @@ import java.time.LocalDateTime; * @author LeeYan9 */ @Data -public class PayOrderInfoCreateReqDTO implements Serializable { +public class PayOrderCreateReqDTO implements Serializable { /** * 应用编号 diff --git a/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/refund/PayRefundApi.java b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/refund/PayRefundApi.java new file mode 100644 index 000000000..50da36e33 --- /dev/null +++ b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/refund/PayRefundApi.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.pay.api.refund; + +import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO; + +import javax.validation.Valid; + +/** + * 退款单 API 接口 + * + * @author 芋道源码 + */ +public interface PayRefundApi { + + /** + * 创建退款单 + * + * @param reqDTO 创建请求 + * @return 退款单编号 + */ + Long createPayRefund(@Valid PayRefundCreateReqDTO reqDTO); + +} diff --git a/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/refund/dto/PayRefundCreateReqDTO.java b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/refund/dto/PayRefundCreateReqDTO.java new file mode 100644 index 000000000..03c552640 --- /dev/null +++ b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/refund/dto/PayRefundCreateReqDTO.java @@ -0,0 +1,52 @@ +package cn.iocoder.yudao.module.pay.api.refund.dto; + +import lombok.Data; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.Min; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +/** + * 退款单创建 Request DTO + * + * @author 芋道源码 + */ +@Data +public class PayRefundCreateReqDTO { + + /** + * 应用编号 + */ + @NotNull(message = "应用编号不能为空") + private Long appId; + /** + * 用户 IP + */ + @NotEmpty(message = "用户 IP 不能为空") + private String userIp; + + // ========== 商户相关字段 ========== + + /** + * 商户订单编号 + */ + @NotEmpty(message = "商户订单编号不能为空") + private String merchantOrderId; + + /** + * 退款描述 + */ + @NotEmpty(message = "退款描述不能为空") + @Length(max = 128, message = "退款描述长度不能超过128") + private String reason; + + // ========== 订单相关字段 ========== + + /** + * 退款金额,单位:分 + */ + @NotNull(message = "退款金额不能为空") + @Min(value = 1, message = "退款金额必须大于零") + private Integer amount; +} diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/PayOrderApiImpl.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/PayOrderApiImpl.java deleted file mode 100644 index d5dd64146..000000000 --- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/PayOrderApiImpl.java +++ /dev/null @@ -1,18 +0,0 @@ -package cn.iocoder.yudao.module.pay.api; - -import cn.iocoder.yudao.module.pay.api.order.PayOrderApi; -import cn.iocoder.yudao.module.pay.api.order.PayOrderInfoCreateReqDTO; -import org.springframework.stereotype.Service; - -/** - * TODO 注释 - */ -@Service -public class PayOrderApiImpl implements PayOrderApi { - - @Override - public Long createPayOrder(PayOrderInfoCreateReqDTO reqDTO) { - return null; - } - -} diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderApiImpl.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderApiImpl.java index 6f2556d35..e5a3186e8 100644 --- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderApiImpl.java +++ b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderApiImpl.java @@ -1,19 +1,17 @@ -//package cn.iocoder.yudao.module.pay.api.order; -// -//import org.springframework.stereotype.Service; -//import org.springframework.transaction.annotation.Transactional; -// -///** -// * @author LeeYan9 -// * @since 2022-09-06 -// */ -//@Service -//public class PayOrderApiImpl implements PayOrderApi { -// -// @Override -// @Transactional(rollbackFor = Exception.class) -// public Long createPayOrder(PayOrderInfoCreateReqDTO reqDTO) { -// return null; -// } -// -//} +package cn.iocoder.yudao.module.pay.api.order; + +import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO; +import org.springframework.stereotype.Service; + +/** + * TODO 注释 + */ +@Service +public class PayOrderApiImpl implements PayOrderApi { + + @Override + public Long createPayOrder(PayOrderCreateReqDTO reqDTO) { + return null; + } + +} diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/refund/PayRefundApiImpl.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/refund/PayRefundApiImpl.java new file mode 100644 index 000000000..27a50572a --- /dev/null +++ b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/refund/PayRefundApiImpl.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.pay.api.refund; + +import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +/** + * 退款单 API 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class PayRefundApiImpl implements PayRefundApi { + + @Override + public Long createPayRefund(PayRefundCreateReqDTO reqDTO) { + // TODO 芋艿:暂未实现 + return null; + } +}