Commit ee1d362a7ccac4c917ac2ae8ccbda0663683ec77
1 parent
67050eea
trade:【交易售后】回调退款
Showing
12 changed files
with
134 additions
and
8 deletions
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java
| @@ -34,6 +34,9 @@ public interface ErrorCodeConstants { | @@ -34,6 +34,9 @@ public interface ErrorCodeConstants { | ||
| 34 | ErrorCode AFTER_SALE_UPDATE_STATUS_FAIL = new ErrorCode(1011000107, "操作售后单失败,请刷新后重试"); | 34 | ErrorCode AFTER_SALE_UPDATE_STATUS_FAIL = new ErrorCode(1011000107, "操作售后单失败,请刷新后重试"); |
| 35 | ErrorCode AFTER_SALE_DELIVERY_FAIL_STATUS_NOT_SELLER_PASS = new ErrorCode(1011000108, "退货失败,售后单状态不处于【待买家退货】"); | 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, "确认收货失败,售后单状态不处于【待确认收货】"); | 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, "退款失败,售后单状态不是【待退款】"); | ||
| 37 | 40 | ||
| 38 | // ========== Cart 模块 1-011-001-000 ========== | 41 | // ========== Cart 模块 1-011-001-000 ========== |
| 39 | ErrorCode CARD_ITEM_NOT_FOUND = new ErrorCode(1011002000, "购物车项不存在"); | 42 | ErrorCode CARD_ITEM_NOT_FOUND = new ErrorCode(1011002000, "购物车项不存在"); |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/TradeAfterSaleController.java
| @@ -5,16 +5,15 @@ import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSal | @@ -5,16 +5,15 @@ import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSal | ||
| 5 | import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleConfirmReqVO; | 5 | import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleConfirmReqVO; |
| 6 | import cn.iocoder.yudao.module.trade.service.aftersale.TradeAfterSaleService; | 6 | import cn.iocoder.yudao.module.trade.service.aftersale.TradeAfterSaleService; |
| 7 | import io.swagger.annotations.Api; | 7 | import io.swagger.annotations.Api; |
| 8 | +import io.swagger.annotations.ApiImplicitParam; | ||
| 8 | import io.swagger.annotations.ApiOperation; | 9 | import io.swagger.annotations.ApiOperation; |
| 9 | import lombok.extern.slf4j.Slf4j; | 10 | import lombok.extern.slf4j.Slf4j; |
| 10 | import org.springframework.security.access.prepost.PreAuthorize; | 11 | import org.springframework.security.access.prepost.PreAuthorize; |
| 11 | import org.springframework.validation.annotation.Validated; | 12 | import org.springframework.validation.annotation.Validated; |
| 12 | -import org.springframework.web.bind.annotation.PutMapping; | ||
| 13 | -import org.springframework.web.bind.annotation.RequestBody; | ||
| 14 | -import org.springframework.web.bind.annotation.RequestMapping; | ||
| 15 | -import org.springframework.web.bind.annotation.RestController; | 13 | +import org.springframework.web.bind.annotation.*; |
| 16 | 14 | ||
| 17 | import javax.annotation.Resource; | 15 | import javax.annotation.Resource; |
| 16 | +import javax.annotation.security.PermitAll; | ||
| 18 | 17 | ||
| 19 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | 18 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 20 | import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP; | 19 | import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP; |
| @@ -46,4 +45,13 @@ public class TradeAfterSaleController { | @@ -46,4 +45,13 @@ public class TradeAfterSaleController { | ||
| 46 | return success(true); | 45 | return success(true); |
| 47 | } | 46 | } |
| 48 | 47 | ||
| 48 | + @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); | ||
| 54 | + return success(true); | ||
| 55 | + } | ||
| 56 | + | ||
| 49 | } | 57 | } |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/aftersale/TradeAfterSaleDO.java
| @@ -125,12 +125,17 @@ public class TradeAfterSaleDO extends BaseDO { | @@ -125,12 +125,17 @@ public class TradeAfterSaleDO extends BaseDO { | ||
| 125 | */ | 125 | */ |
| 126 | private Integer refundPrice; | 126 | private Integer refundPrice; |
| 127 | /** | 127 | /** |
| 128 | - * 支付退款编号 TODO | 128 | + * 支付退款编号 |
| 129 | * | 129 | * |
| 130 | * 对接 pay-module-biz 支付服务的退款订单编号,即 PayRefundDO 的 id 编号 | 130 | * 对接 pay-module-biz 支付服务的退款订单编号,即 PayRefundDO 的 id 编号 |
| 131 | */ | 131 | */ |
| 132 | private Long payRefundId; | 132 | private Long payRefundId; |
| 133 | - // TODO 芋艿:看看是否有必要冗余,order_number、order_amount、flow_trade_no、out_refund_no、pay_type、return_money_sts、refund_time | 133 | + /** |
| 134 | + * 退款时间 | ||
| 135 | + * | ||
| 136 | + * 退款成功后,才记录该时间 | ||
| 137 | + */ | ||
| 138 | + private LocalDateTime refundTime; | ||
| 134 | 139 | ||
| 135 | // ========== 退货相关 ========== | 140 | // ========== 退货相关 ========== |
| 136 | /** | 141 | /** |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/aftersale/TradeAfterSaleMapper.java
| @@ -13,4 +13,8 @@ public interface TradeAfterSaleMapper extends BaseMapperX<TradeAfterSaleDO> { | @@ -13,4 +13,8 @@ public interface TradeAfterSaleMapper extends BaseMapperX<TradeAfterSaleDO> { | ||
| 13 | .eq(TradeAfterSaleDO::getId, id).eq(TradeAfterSaleDO::getStatus, status)); | 13 | .eq(TradeAfterSaleDO::getId, id).eq(TradeAfterSaleDO::getStatus, status)); |
| 14 | } | 14 | } |
| 15 | 15 | ||
| 16 | + default TradeAfterSaleDO selectByPayRefundId(Long payRefundId) { | ||
| 17 | + return selectOne(TradeAfterSaleDO::getPayRefundId, payRefundId); | ||
| 18 | + } | ||
| 19 | + | ||
| 16 | } | 20 | } |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleService.java
| @@ -49,4 +49,11 @@ public interface TradeAfterSaleService { | @@ -49,4 +49,11 @@ public interface TradeAfterSaleService { | ||
| 49 | */ | 49 | */ |
| 50 | void confirmAfterSale(Long userId, String userIp, TradeAfterSaleConfirmReqVO confirmReqVO); | 50 | void confirmAfterSale(Long userId, String userIp, TradeAfterSaleConfirmReqVO confirmReqVO); |
| 51 | 51 | ||
| 52 | + /** | ||
| 53 | + * 确认退款,由【pay】支付服务回调 | ||
| 54 | + * | ||
| 55 | + * @param payRefundId 支付退款编号 | ||
| 56 | + */ | ||
| 57 | + void refundAfterSale(Long payRefundId); | ||
| 58 | + | ||
| 52 | } | 59 | } |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceImpl.java
| @@ -4,6 +4,8 @@ import cn.hutool.core.util.ObjectUtil; | @@ -4,6 +4,8 @@ import cn.hutool.core.util.ObjectUtil; | ||
| 4 | import cn.hutool.core.util.RandomUtil; | 4 | import cn.hutool.core.util.RandomUtil; |
| 5 | import cn.iocoder.yudao.module.pay.api.refund.PayRefundApi; | 5 | import cn.iocoder.yudao.module.pay.api.refund.PayRefundApi; |
| 6 | import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO; | 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; | ||
| 7 | import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleAuditReqVO; | 9 | import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleAuditReqVO; |
| 8 | import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleConfirmReqVO; | 10 | import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.TradeAfterSaleConfirmReqVO; |
| 9 | import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppTradeAfterSaleCreateReqVO; | 11 | import cn.iocoder.yudao.module.trade.controller.app.aftersale.vo.AppTradeAfterSaleCreateReqVO; |
| @@ -276,4 +278,42 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService { | @@ -276,4 +278,42 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService { | ||
| 276 | // TODO 发送售后消息 | 278 | // TODO 发送售后消息 |
| 277 | } | 279 | } |
| 278 | 280 | ||
| 281 | + @Override | ||
| 282 | + public void refundAfterSale(Long payRefundId) { | ||
| 283 | + // 校验退款单 | ||
| 284 | + PayRefundRespDTO payRefund = validatePayRefundSuccess(payRefundId); | ||
| 285 | + | ||
| 286 | + // 校验售后单的状态,并状态待退款 | ||
| 287 | + TradeAfterSaleDO afterSale = tradeAfterSaleMapper.selectByPayRefundId(payRefundId); | ||
| 288 | + if (afterSale == null) { | ||
| 289 | + throw exception(AFTER_SALE_NOT_FOUND); | ||
| 290 | + } | ||
| 291 | + if (ObjectUtil.notEqual(afterSale.getStatus(), TradeAfterSaleStatusEnum.WAIT_REFUND.getStatus())) { | ||
| 292 | + throw exception(AFTER_SALE_REFUND_FAIL_STATUS_NOT_WAIT_REFUND); | ||
| 293 | + } | ||
| 294 | + | ||
| 295 | + // 更新售后单的状态为【已完成】 | ||
| 296 | + 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()); | ||
| 302 | + | ||
| 303 | + // TODO 记录售后日志 | ||
| 304 | + | ||
| 305 | + // TODO 发送售后消息 | ||
| 306 | + } | ||
| 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; | ||
| 317 | + } | ||
| 318 | + | ||
| 279 | } | 319 | } |
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/refund/PayRefundApi.java
| 1 | package cn.iocoder.yudao.module.pay.api.refund; | 1 | package cn.iocoder.yudao.module.pay.api.refund; |
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO; | 3 | import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO; |
| 4 | +import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundRespDTO; | ||
| 4 | 5 | ||
| 5 | import javax.validation.Valid; | 6 | import javax.validation.Valid; |
| 6 | 7 | ||
| @@ -19,4 +20,12 @@ public interface PayRefundApi { | @@ -19,4 +20,12 @@ public interface PayRefundApi { | ||
| 19 | */ | 20 | */ |
| 20 | Long createPayRefund(@Valid PayRefundCreateReqDTO reqDTO); | 21 | Long createPayRefund(@Valid PayRefundCreateReqDTO reqDTO); |
| 21 | 22 | ||
| 23 | + /** | ||
| 24 | + * 获得退款单 | ||
| 25 | + * | ||
| 26 | + * @param id 退款单编号 | ||
| 27 | + * @return 退款单 | ||
| 28 | + */ | ||
| 29 | + PayRefundRespDTO getPayRefund(Long id); | ||
| 30 | + | ||
| 22 | } | 31 | } |
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/refund/dto/PayRefundRespDTO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.pay.api.refund.dto; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum; | ||
| 4 | +import lombok.Data; | ||
| 5 | + | ||
| 6 | +import java.time.LocalDateTime; | ||
| 7 | + | ||
| 8 | +/** | ||
| 9 | + * 退款单信息 Response DTO | ||
| 10 | + * | ||
| 11 | + * TODO 芋艿:还没定好字段 | ||
| 12 | + * | ||
| 13 | + * @author 芋道源码 | ||
| 14 | + */ | ||
| 15 | +@Data | ||
| 16 | +public class PayRefundRespDTO { | ||
| 17 | + | ||
| 18 | + /** | ||
| 19 | + * 退款单编号 | ||
| 20 | + */ | ||
| 21 | + private Long id; | ||
| 22 | + | ||
| 23 | + // ========== 退款相关字段 ========== | ||
| 24 | + /** | ||
| 25 | + * 退款状态 | ||
| 26 | + * | ||
| 27 | + * 枚举 {@link PayRefundStatusEnum} | ||
| 28 | + */ | ||
| 29 | + private Integer status; | ||
| 30 | + | ||
| 31 | + // ========== 渠道相关字段 ========== | ||
| 32 | + /** | ||
| 33 | + * 退款成功时间 | ||
| 34 | + */ | ||
| 35 | + private LocalDateTime successTime; | ||
| 36 | + | ||
| 37 | +} |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/enums/order/PayOrderStatusEnum.java renamed to yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/order/PayOrderStatusEnum.java
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/enums/refund/PayRefundStatusEnum.java renamed to yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/refund/PayRefundStatusEnum.java
| @@ -3,6 +3,8 @@ package cn.iocoder.yudao.module.pay.enums.refund; | @@ -3,6 +3,8 @@ package cn.iocoder.yudao.module.pay.enums.refund; | ||
| 3 | import lombok.AllArgsConstructor; | 3 | import lombok.AllArgsConstructor; |
| 4 | import lombok.Getter; | 4 | import lombok.Getter; |
| 5 | 5 | ||
| 6 | +import java.util.Objects; | ||
| 7 | + | ||
| 6 | @Getter | 8 | @Getter |
| 7 | @AllArgsConstructor | 9 | @AllArgsConstructor |
| 8 | public enum PayRefundStatusEnum { | 10 | public enum PayRefundStatusEnum { |
| @@ -14,4 +16,9 @@ public enum PayRefundStatusEnum { | @@ -14,4 +16,9 @@ public enum PayRefundStatusEnum { | ||
| 14 | 16 | ||
| 15 | private final Integer status; | 17 | private final Integer status; |
| 16 | private final String name; | 18 | private final String name; |
| 19 | + | ||
| 20 | + public static boolean isSuccess(Integer status) { | ||
| 21 | + return Objects.equals(status, SUCCESS.getStatus()); | ||
| 22 | + } | ||
| 23 | + | ||
| 17 | } | 24 | } |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/refund/PayRefundApiImpl.java
| 1 | package cn.iocoder.yudao.module.pay.api.refund; | 1 | package cn.iocoder.yudao.module.pay.api.refund; |
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO; | 3 | import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO; |
| 4 | +import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundRespDTO; | ||
| 4 | import org.springframework.stereotype.Service; | 5 | import org.springframework.stereotype.Service; |
| 5 | import org.springframework.validation.annotation.Validated; | 6 | import org.springframework.validation.annotation.Validated; |
| 6 | 7 | ||
| @@ -18,4 +19,11 @@ public class PayRefundApiImpl implements PayRefundApi { | @@ -18,4 +19,11 @@ public class PayRefundApiImpl implements PayRefundApi { | ||
| 18 | // TODO 芋艿:暂未实现 | 19 | // TODO 芋艿:暂未实现 |
| 19 | return null; | 20 | return null; |
| 20 | } | 21 | } |
| 22 | + | ||
| 23 | + @Override | ||
| 24 | + public PayRefundRespDTO getPayRefund(Long id) { | ||
| 25 | + // TODO 芋艿:暂未实现 | ||
| 26 | + return null; | ||
| 27 | + } | ||
| 28 | + | ||
| 21 | } | 29 | } |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/refund/PayRefundDO.java