pay:示例订单,接入退款回调逻辑
This commit is contained in:
parent
eb660ca619
commit
44b0346e5e
|
@ -1,5 +1,6 @@
|
||||||
package cn.iocoder.yudao.module.pay.api.notify.dto;
|
package cn.iocoder.yudao.module.pay.api.notify.dto;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
@ -31,12 +32,4 @@ public class PayRefundNotifyReqDTO {
|
||||||
@NotNull(message = "支付退款编号不能为空")
|
@NotNull(message = "支付退款编号不能为空")
|
||||||
private Long payRefundId;
|
private Long payRefundId;
|
||||||
|
|
||||||
/**
|
|
||||||
* 退款状态
|
|
||||||
*
|
|
||||||
* (成功,失败) TODO 芋艿:枚举
|
|
||||||
*/
|
|
||||||
@NotNull(message = "退款状态不能为空")
|
|
||||||
private Integer status;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,12 +28,6 @@ public class PayRefundCreateReqDTO {
|
||||||
|
|
||||||
// ========== 商户相关字段 ==========
|
// ========== 商户相关字段 ==========
|
||||||
|
|
||||||
/**
|
|
||||||
* 商户订单编号
|
|
||||||
*/
|
|
||||||
@NotEmpty(message = "商户订单编号不能为空")
|
|
||||||
private String merchantOrderId;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 退款描述
|
* 退款描述
|
||||||
*/
|
*/
|
||||||
|
@ -43,6 +37,12 @@ public class PayRefundCreateReqDTO {
|
||||||
|
|
||||||
// ========== 订单相关字段 ==========
|
// ========== 订单相关字段 ==========
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支付单号
|
||||||
|
*/
|
||||||
|
@NotNull(message = "支付单号不能为空")
|
||||||
|
private Long payOrderId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 退款金额,单位:分
|
* 退款金额,单位:分
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -27,8 +27,16 @@ public class PayRefundRespDTO {
|
||||||
* 枚举 {@link PayRefundStatusEnum}
|
* 枚举 {@link PayRefundStatusEnum}
|
||||||
*/
|
*/
|
||||||
private Integer status;
|
private Integer status;
|
||||||
|
/**
|
||||||
|
* 退款金额,单位:分
|
||||||
|
*/
|
||||||
|
private Integer refundAmount;
|
||||||
|
|
||||||
// ========== 渠道相关字段 ==========
|
// ========== 商户相关字段 ==========
|
||||||
|
/**
|
||||||
|
* 商户订单编号
|
||||||
|
*/
|
||||||
|
private String merchantOrderId;
|
||||||
/**
|
/**
|
||||||
* 退款成功时间
|
* 退款成功时间
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -51,21 +51,23 @@ public interface ErrorCodeConstants {
|
||||||
ErrorCode PAY_REFUND_SUCCEED = new ErrorCode(1007006003, "已经退款成功");
|
ErrorCode PAY_REFUND_SUCCEED = new ErrorCode(1007006003, "已经退款成功");
|
||||||
ErrorCode PAY_REFUND_NOT_FOUND = new ErrorCode(1007006004, "支付退款单不存在");
|
ErrorCode PAY_REFUND_NOT_FOUND = new ErrorCode(1007006004, "支付退款单不存在");
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ========== 支付商户信息 1-007-004-000 ==========
|
* ========== 支付商户信息 1-007-004-000 ==========
|
||||||
*/
|
*/
|
||||||
ErrorCode PAY_MERCHANT_NOT_EXISTS = new ErrorCode(1007004000, "支付商户信息不存在");
|
ErrorCode PAY_MERCHANT_NOT_EXISTS = new ErrorCode(1007004000, "支付商户信息不存在");
|
||||||
ErrorCode PAY_MERCHANT_EXIST_APP_CANT_DELETE = new ErrorCode(1007004001, "支付商户存在支付应用,无法删除");
|
ErrorCode PAY_MERCHANT_EXIST_APP_CANT_DELETE = new ErrorCode(1007004001, "支付商户存在支付应用,无法删除");
|
||||||
|
|
||||||
|
|
||||||
// ========== 示例订单 1-007-900-000 ==========
|
// ========== 示例订单 1-007-900-000 ==========
|
||||||
ErrorCode PAY_DEMO_ORDER_NOT_FOUND = new ErrorCode(100790000, "示例订单不存在");
|
ErrorCode PAY_DEMO_ORDER_NOT_FOUND = new ErrorCode(100790000, "示例订单不存在");
|
||||||
ErrorCode PAY_DEMO_ORDER_UPDATE_PAID_STATUS_NOT_UNPAID = new ErrorCode(100790001, "示例订单更新支付状态失败,订单不是【未支付】状态");
|
ErrorCode PAY_DEMO_ORDER_UPDATE_PAID_STATUS_NOT_UNPAID = new ErrorCode(100790001, "示例订单更新支付状态失败,订单不是【未支付】状态");
|
||||||
ErrorCode PAY_DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_ID_ERROR = new ErrorCode(100790002, "示例订单更新支付状态失败,支付单编号不匹配");
|
ErrorCode PAY_DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_ID_ERROR = new ErrorCode(100790002, "示例订单更新支付状态失败,支付单编号不匹配");
|
||||||
ErrorCode PAY_DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_STATUS_NOT_SUCCESS = new ErrorCode(100790003, "示例订单更新支付状态失败,支付单状态不是【支付成功】状态");
|
ErrorCode PAY_DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_STATUS_NOT_SUCCESS = new ErrorCode(100790003, "示例订单更新支付状态失败,支付单状态不是【支付成功】状态");
|
||||||
ErrorCode PAY_DEMO_ORDER_UPDATE_PAID_FAIL_PAY_PRICE_NOT_MATCH = new ErrorCode(100790004, "示例订单更新支付状态失败,支付单金额不匹配");
|
ErrorCode PAY_DEMO_ORDER_UPDATE_PAID_FAIL_PAY_PRICE_NOT_MATCH = new ErrorCode(100790004, "示例订单更新支付状态失败,支付单金额不匹配");
|
||||||
ErrorCode PAY_DEMO_ORDER_REFUND_FAIL_NOT_PAID = new ErrorCode(100790005, "发起退款失败,原因:示例订单未支付");
|
ErrorCode PAY_DEMO_ORDER_REFUND_FAIL_NOT_PAID = new ErrorCode(100790005, "发起退款失败,示例订单未支付");
|
||||||
ErrorCode PAY_DEMO_ORDER_REFUND_FAIL_REFUNDED = new ErrorCode(100790005, "发起退款失败,原因:示例订单已退款");
|
ErrorCode PAY_DEMO_ORDER_REFUND_FAIL_REFUNDED = new ErrorCode(100790006, "发起退款失败,示例订单已退款");
|
||||||
|
ErrorCode PAY_DEMO_ORDER_REFUND_FAIL_REFUND_NOT_FOUND = new ErrorCode(100790007, "发起退款失败,退款订单不存在");
|
||||||
|
ErrorCode PAY_DEMO_ORDER_REFUND_FAIL_REFUND_NOT_SUCCESS = new ErrorCode(100790008, "发起退款失败,退款订单未退款成功");
|
||||||
|
ErrorCode PAY_DEMO_ORDER_REFUND_FAIL_REFUND_ORDER_ID_ERROR = new ErrorCode(100790008, "发起退款失败,退款单编号不匹配");
|
||||||
|
ErrorCode PAY_DEMO_ORDER_REFUND_FAIL_REFUND_PRICE_NOT_MATCH = new ErrorCode(100790004, "发起退款失败,退款单金额不匹配");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,12 @@ package cn.iocoder.yudao.module.pay.api.refund;
|
||||||
|
|
||||||
import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO;
|
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.api.refund.dto.PayRefundRespDTO;
|
||||||
|
import cn.iocoder.yudao.module.pay.service.refund.PayRefundService;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 退款单 API 实现类
|
* 退款单 API 实现类
|
||||||
*
|
*
|
||||||
|
@ -14,10 +17,12 @@ import org.springframework.validation.annotation.Validated;
|
||||||
@Validated
|
@Validated
|
||||||
public class PayRefundApiImpl implements PayRefundApi {
|
public class PayRefundApiImpl implements PayRefundApi {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private PayRefundService payRefundService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Long createPayRefund(PayRefundCreateReqDTO reqDTO) {
|
public Long createPayRefund(PayRefundCreateReqDTO reqDTO) {
|
||||||
// TODO 芋艿:暂未实现
|
return payRefundService.createPayRefund(reqDTO);
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
|
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
|
||||||
import cn.iocoder.yudao.module.pay.api.notify.dto.PayOrderNotifyReqDTO;
|
import cn.iocoder.yudao.module.pay.api.notify.dto.PayOrderNotifyReqDTO;
|
||||||
|
import cn.iocoder.yudao.module.pay.api.notify.dto.PayRefundNotifyReqDTO;
|
||||||
import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.PayDemoOrderCreateReqVO;
|
import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.PayDemoOrderCreateReqVO;
|
||||||
import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.PayDemoOrderRespVO;
|
import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.PayDemoOrderRespVO;
|
||||||
import cn.iocoder.yudao.module.pay.convert.demo.PayDemoOrderConvert;
|
import cn.iocoder.yudao.module.pay.convert.demo.PayDemoOrderConvert;
|
||||||
|
@ -12,7 +13,6 @@ import cn.iocoder.yudao.module.pay.dal.dataobject.demo.PayDemoOrderDO;
|
||||||
import cn.iocoder.yudao.module.pay.service.demo.PayDemoOrderService;
|
import cn.iocoder.yudao.module.pay.service.demo.PayDemoOrderService;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.Parameter;
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
@ -58,11 +58,21 @@ public class PayDemoOrderController {
|
||||||
}
|
}
|
||||||
|
|
||||||
@PutMapping("/refund")
|
@PutMapping("/refund")
|
||||||
@Operation(description = "退款示例订单")
|
@Operation(description = "发起示例订单的退款")
|
||||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||||
public CommonResult<Boolean> refundDemoOrder(@RequestParam("id") Long id) {
|
public CommonResult<Boolean> refundDemoOrder(@RequestParam("id") Long id) {
|
||||||
payDemoOrderService.refundDemoOrder(id, getClientIP());
|
payDemoOrderService.refundDemoOrder(id, getClientIP());
|
||||||
return success(true);
|
return success(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/update-refunded")
|
||||||
|
@Operation(description = "更新示例订单为已退款") // 由 pay-module 支付服务,进行回调,可见 PayNotifyJob
|
||||||
|
@PermitAll // 无需登录,安全由 PayDemoOrderService 内部校验实现
|
||||||
|
@OperateLog(enable = false) // 禁用操作日志,因为没有操作人
|
||||||
|
public CommonResult<Boolean> updateDemoOrderRefunded(@RequestBody PayRefundNotifyReqDTO notifyReqDTO) {
|
||||||
|
payDemoOrderService.updateDemoOrderRefunded(Long.valueOf(notifyReqDTO.getMerchantOrderId()),
|
||||||
|
notifyReqDTO.getPayRefundId());
|
||||||
|
return success(true);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,47 +0,0 @@
|
||||||
package cn.iocoder.yudao.module.pay.controller.app.refund;
|
|
||||||
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
|
||||||
import cn.iocoder.yudao.module.pay.controller.app.refund.vo.AppPayRefundReqVO;
|
|
||||||
import cn.iocoder.yudao.module.pay.controller.app.refund.vo.AppPayRefundRespVO;
|
|
||||||
import cn.iocoder.yudao.module.pay.convert.refund.PayRefundConvert;
|
|
||||||
import cn.iocoder.yudao.module.pay.service.order.dto.PayRefundReqDTO;
|
|
||||||
import cn.iocoder.yudao.module.pay.service.refund.PayRefundService;
|
|
||||||
import cn.iocoder.yudao.module.pay.util.PaySeqUtils;
|
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
|
||||||
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;
|
|
||||||
|
|
||||||
@Tag(name = "用户 APP - 退款订单")
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/pay/refund")
|
|
||||||
@Validated
|
|
||||||
@Slf4j
|
|
||||||
public class AppPayRefundController {
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private PayRefundService refundService;
|
|
||||||
|
|
||||||
@PostMapping("/refund")
|
|
||||||
@Operation(summary = "提交退款订单")
|
|
||||||
public CommonResult<AppPayRefundRespVO> submitRefundOrder(@RequestBody AppPayRefundReqVO reqVO){
|
|
||||||
PayRefundReqDTO req = PayRefundConvert.INSTANCE.convert(reqVO);
|
|
||||||
req.setUserIp(getClientIP());
|
|
||||||
// TODO 测试暂时模拟生成商户退款订单
|
|
||||||
if(StrUtil.isEmpty(reqVO.getMerchantRefundId())) {
|
|
||||||
req.setMerchantRefundId(PaySeqUtils.genMerchantRefundNo());
|
|
||||||
}
|
|
||||||
return success(PayRefundConvert.INSTANCE.convert(refundService.submitRefundOrder(req)));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
/**
|
||||||
|
* TODO 芋艿:占个位置,没啥用
|
||||||
|
*/
|
||||||
|
package cn.iocoder.yudao.module.pay.controller.app.refund;
|
|
@ -1,34 +0,0 @@
|
||||||
package cn.iocoder.yudao.module.pay.controller.app.refund.vo;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
|
|
||||||
import javax.validation.constraints.NotEmpty;
|
|
||||||
import javax.validation.constraints.NotNull;
|
|
||||||
|
|
||||||
@Schema(description = "用户 APP - 退款订单 Req VO")
|
|
||||||
@Data
|
|
||||||
@NoArgsConstructor
|
|
||||||
@AllArgsConstructor
|
|
||||||
public class AppPayRefundReqVO {
|
|
||||||
|
|
||||||
@Schema(description = "支付订单编号自增", required = true, example = "10")
|
|
||||||
@NotNull(message = "支付订单编号自增")
|
|
||||||
private Long payOrderId;
|
|
||||||
|
|
||||||
@Schema(description = "退款金额", required = true, example = "1")
|
|
||||||
@NotNull(message = "退款金额")
|
|
||||||
private Long amount;
|
|
||||||
|
|
||||||
@Schema(description = "退款原因", required = true, example = "不喜欢")
|
|
||||||
@NotEmpty(message = "退款原因")
|
|
||||||
private String reason;
|
|
||||||
|
|
||||||
@Schema(description = "商户退款订单号", required = true, example = "MR202111180000000001")
|
|
||||||
//TODO 测试暂时模拟生成
|
|
||||||
//@NotEmpty(message = "商户退款订单号")
|
|
||||||
private String merchantRefundId;
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
package cn.iocoder.yudao.module.pay.controller.app.refund.vo;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Builder;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
import lombok.experimental.Accessors;
|
|
||||||
|
|
||||||
@Schema(description = "用户 APP - 提交退款订单 Response VO")
|
|
||||||
@Data
|
|
||||||
@Accessors(chain = true)
|
|
||||||
@Builder
|
|
||||||
@NoArgsConstructor
|
|
||||||
@AllArgsConstructor
|
|
||||||
public class AppPayRefundRespVO {
|
|
||||||
|
|
||||||
@Schema(description = "退款订单编号", required = true, example = "10")
|
|
||||||
private Long refundId;
|
|
||||||
|
|
||||||
}
|
|
|
@ -2,12 +2,8 @@ package cn.iocoder.yudao.module.pay.convert.refund;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.*;
|
import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.*;
|
||||||
import cn.iocoder.yudao.module.pay.controller.app.refund.vo.AppPayRefundReqVO;
|
|
||||||
import cn.iocoder.yudao.module.pay.controller.app.refund.vo.AppPayRefundRespVO;
|
|
||||||
import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
|
import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
|
||||||
import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO;
|
import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO;
|
||||||
import cn.iocoder.yudao.module.pay.service.order.dto.PayRefundReqDTO;
|
|
||||||
import cn.iocoder.yudao.module.pay.service.order.dto.PayRefundRespDTO;
|
|
||||||
import org.mapstruct.Mapper;
|
import org.mapstruct.Mapper;
|
||||||
import org.mapstruct.Mapping;
|
import org.mapstruct.Mapping;
|
||||||
import org.mapstruct.Mappings;
|
import org.mapstruct.Mappings;
|
||||||
|
@ -17,11 +13,6 @@ import java.math.BigDecimal;
|
||||||
import java.math.RoundingMode;
|
import java.math.RoundingMode;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
|
||||||
* 退款订单 Convert
|
|
||||||
*
|
|
||||||
* @author aquan
|
|
||||||
*/
|
|
||||||
@Mapper
|
@Mapper
|
||||||
public interface PayRefundConvert {
|
public interface PayRefundConvert {
|
||||||
|
|
||||||
|
@ -102,8 +93,4 @@ public interface PayRefundConvert {
|
||||||
})
|
})
|
||||||
PayRefundDO convert(PayOrderDO orderDO);
|
PayRefundDO convert(PayOrderDO orderDO);
|
||||||
|
|
||||||
PayRefundReqDTO convert(AppPayRefundReqVO bean);
|
|
||||||
|
|
||||||
AppPayRefundRespVO convert(PayRefundRespDTO bean);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,6 +83,6 @@ public class PayDemoOrderDO extends BaseDO {
|
||||||
/**
|
/**
|
||||||
* 退款完成时间
|
* 退款完成时间
|
||||||
*/
|
*/
|
||||||
private Date refundTime;
|
private LocalDateTime refundTime;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,7 +80,6 @@ public class PayRefundDO extends BaseDO {
|
||||||
*/
|
*/
|
||||||
private String tradeNo;
|
private String tradeNo;
|
||||||
|
|
||||||
|
|
||||||
// ========== 商户相关字段 ==========
|
// ========== 商户相关字段 ==========
|
||||||
/**
|
/**
|
||||||
* 商户订单编号
|
* 商户订单编号
|
||||||
|
@ -171,14 +170,12 @@ public class PayRefundDO extends BaseDO {
|
||||||
*/
|
*/
|
||||||
private String channelErrorMsg;
|
private String channelErrorMsg;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 支付渠道的额外参数
|
* 支付渠道的额外参数
|
||||||
* 参见 https://www.pingxx.com/api/Refunds%20退款概述.html
|
* 参见 https://www.pingxx.com/api/Refunds%20退款概述.html
|
||||||
*/
|
*/
|
||||||
private String channelExtras;
|
private String channelExtras;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO
|
* TODO
|
||||||
* 退款失效时间
|
* 退款失效时间
|
||||||
|
@ -193,5 +190,4 @@ public class PayRefundDO extends BaseDO {
|
||||||
*/
|
*/
|
||||||
private LocalDateTime notifyTime;
|
private LocalDateTime notifyTime;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,11 +48,19 @@ public interface PayDemoOrderService {
|
||||||
void updateDemoOrderPaid(Long id, Long payOrderId);
|
void updateDemoOrderPaid(Long id, Long payOrderId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 退款示例订单
|
* 发起示例订单的退款
|
||||||
*
|
*
|
||||||
* @param id 编号
|
* @param id 编号
|
||||||
* @param userIp 用户编号
|
* @param userIp 用户编号
|
||||||
*/
|
*/
|
||||||
void refundDemoOrder(Long id, String userIp);
|
void refundDemoOrder(Long id, String userIp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新示例订单为已退款
|
||||||
|
*
|
||||||
|
* @param id 编号
|
||||||
|
* @param payRefundId 退款订单号
|
||||||
|
*/
|
||||||
|
void updateDemoOrderRefunded(Long id, Long payRefundId);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,10 +10,12 @@ import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;
|
||||||
import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderRespDTO;
|
import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderRespDTO;
|
||||||
import cn.iocoder.yudao.module.pay.api.refund.PayRefundApi;
|
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.PayRefundCreateReqDTO;
|
||||||
|
import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundRespDTO;
|
||||||
import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.PayDemoOrderCreateReqVO;
|
import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.PayDemoOrderCreateReqVO;
|
||||||
import cn.iocoder.yudao.module.pay.dal.dataobject.demo.PayDemoOrderDO;
|
import cn.iocoder.yudao.module.pay.dal.dataobject.demo.PayDemoOrderDO;
|
||||||
import cn.iocoder.yudao.module.pay.dal.mysql.demo.PayDemoOrderMapper;
|
import cn.iocoder.yudao.module.pay.dal.mysql.demo.PayDemoOrderMapper;
|
||||||
import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
|
import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
|
||||||
|
import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
@ -23,9 +25,12 @@ import java.time.Duration;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import static cn.hutool.core.util.ObjectUtil.*;
|
||||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||||
import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.addTime;
|
import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.addTime;
|
||||||
|
import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
|
||||||
import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
|
import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
|
||||||
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*;
|
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*;
|
||||||
|
|
||||||
|
@ -137,46 +142,46 @@ public class PayDemoOrderServiceImpl implements PayDemoOrderService {
|
||||||
* @return 交易订单
|
* @return 交易订单
|
||||||
*/
|
*/
|
||||||
private PayOrderRespDTO validateDemoOrderCanPaid(Long id, Long payOrderId) {
|
private PayOrderRespDTO validateDemoOrderCanPaid(Long id, Long payOrderId) {
|
||||||
// 校验订单是否存在
|
// 1.1 校验订单是否存在
|
||||||
PayDemoOrderDO order = payDemoOrderMapper.selectById(id);
|
PayDemoOrderDO order = payDemoOrderMapper.selectById(id);
|
||||||
if (order == null) {
|
if (order == null) {
|
||||||
throw exception(PAY_DEMO_ORDER_NOT_FOUND);
|
throw exception(PAY_DEMO_ORDER_NOT_FOUND);
|
||||||
}
|
}
|
||||||
// 校验订单未支付
|
// 1.2 校验订单未支付
|
||||||
if (order.getPayed()) {
|
if (order.getPayed()) {
|
||||||
log.error("[validateDemoOrderCanPaid][order({}) 不处于待支付状态,请进行处理!order 数据是:{}]",
|
log.error("[validateDemoOrderCanPaid][order({}) 不处于待支付状态,请进行处理!order 数据是:{}]",
|
||||||
id, JsonUtils.toJsonString(order));
|
id, toJsonString(order));
|
||||||
throw exception(PAY_DEMO_ORDER_UPDATE_PAID_STATUS_NOT_UNPAID);
|
throw exception(PAY_DEMO_ORDER_UPDATE_PAID_STATUS_NOT_UNPAID);
|
||||||
}
|
}
|
||||||
// 校验支付订单匹配
|
// 1.3 校验支付订单匹配
|
||||||
if (ObjectUtil.notEqual(order.getPayOrderId(), payOrderId)) { // 支付单号
|
if (notEqual(order.getPayOrderId(), payOrderId)) { // 支付单号
|
||||||
log.error("[validateDemoOrderCanPaid][order({}) 支付单不匹配({}),请进行处理!order 数据是:{}]",
|
log.error("[validateDemoOrderCanPaid][order({}) 支付单不匹配({}),请进行处理!order 数据是:{}]",
|
||||||
id, payOrderId, JsonUtils.toJsonString(order));
|
id, payOrderId, toJsonString(order));
|
||||||
throw exception(PAY_DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_ID_ERROR);
|
throw exception(PAY_DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_ID_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 校验支付单是否存在
|
// 2.1 校验支付单是否存在
|
||||||
PayOrderRespDTO payOrder = payOrderApi.getOrder(payOrderId);
|
PayOrderRespDTO payOrder = payOrderApi.getOrder(payOrderId);
|
||||||
if (payOrder == null) {
|
if (payOrder == null) {
|
||||||
log.error("[validateDemoOrderCanPaid][order({}) payOrder({}) 不存在,请进行处理!]", id, payOrderId);
|
log.error("[validateDemoOrderCanPaid][order({}) payOrder({}) 不存在,请进行处理!]", id, payOrderId);
|
||||||
throw exception(PAY_ORDER_NOT_FOUND);
|
throw exception(PAY_ORDER_NOT_FOUND);
|
||||||
}
|
}
|
||||||
// 校验支付单已支付
|
// 2.2 校验支付单已支付
|
||||||
if (!PayOrderStatusEnum.isSuccess(payOrder.getStatus())) {
|
if (!PayOrderStatusEnum.isSuccess(payOrder.getStatus())) {
|
||||||
log.error("[validateDemoOrderCanPaid][order({}) payOrder({}) 未支付,请进行处理!payOrder 数据是:{}]",
|
log.error("[validateDemoOrderCanPaid][order({}) payOrder({}) 未支付,请进行处理!payOrder 数据是:{}]",
|
||||||
id, payOrderId, JsonUtils.toJsonString(payOrder));
|
id, payOrderId, toJsonString(payOrder));
|
||||||
throw exception(PAY_DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_STATUS_NOT_SUCCESS);
|
throw exception(PAY_DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_STATUS_NOT_SUCCESS);
|
||||||
}
|
}
|
||||||
// 校验支付金额一致
|
// 2.3 校验支付金额一致
|
||||||
if (ObjectUtil.notEqual(payOrder.getAmount(), order.getPrice())) {
|
if (notEqual(payOrder.getAmount(), order.getPrice())) {
|
||||||
log.error("[validateDemoOrderCanPaid][order({}) payOrder({}) 支付金额不匹配,请进行处理!order 数据是:{},payOrder 数据是:{}]",
|
log.error("[validateDemoOrderCanPaid][order({}) payOrder({}) 支付金额不匹配,请进行处理!order 数据是:{},payOrder 数据是:{}]",
|
||||||
id, payOrderId, JsonUtils.toJsonString(order), JsonUtils.toJsonString(payOrder));
|
id, payOrderId, toJsonString(order), toJsonString(payOrder));
|
||||||
throw exception(PAY_DEMO_ORDER_UPDATE_PAID_FAIL_PAY_PRICE_NOT_MATCH);
|
throw exception(PAY_DEMO_ORDER_UPDATE_PAID_FAIL_PAY_PRICE_NOT_MATCH);
|
||||||
}
|
}
|
||||||
// 校验支付订单匹配(二次)
|
// 2.4 校验支付订单匹配(二次)
|
||||||
if (ObjectUtil.notEqual(payOrder.getMerchantOrderId(), id.toString())) {
|
if (notEqual(payOrder.getMerchantOrderId(), id.toString())) {
|
||||||
log.error("[validateDemoOrderCanPaid][order({}) 支付单不匹配({}),请进行处理!payOrder 数据是:{}]",
|
log.error("[validateDemoOrderCanPaid][order({}) 支付单不匹配({}),请进行处理!payOrder 数据是:{}]",
|
||||||
id, payOrderId, JsonUtils.toJsonString(payOrder));
|
id, payOrderId, toJsonString(payOrder));
|
||||||
throw exception(PAY_DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_ID_ERROR);
|
throw exception(PAY_DEMO_ORDER_UPDATE_PAID_FAIL_PAY_ORDER_ID_ERROR);
|
||||||
}
|
}
|
||||||
return payOrder;
|
return payOrder;
|
||||||
|
@ -190,9 +195,9 @@ public class PayDemoOrderServiceImpl implements PayDemoOrderService {
|
||||||
// 2.1 创建退款单
|
// 2.1 创建退款单
|
||||||
Long payRefundId = payRefundApi.createPayRefund(new PayRefundCreateReqDTO()
|
Long payRefundId = payRefundApi.createPayRefund(new PayRefundCreateReqDTO()
|
||||||
.setAppId(PAY_APP_ID).setUserIp(getClientIP()) // 支付应用
|
.setAppId(PAY_APP_ID).setUserIp(getClientIP()) // 支付应用
|
||||||
.setMerchantOrderId(order.getId().toString()) // 业务的订单编号
|
.setPayOrderId(order.getPayOrderId()) // 支付单号
|
||||||
.setReason("想退钱").setAmount(order.getPrice())); // 价格信息
|
.setReason("想退钱").setAmount(order.getPrice()));// 价格信息
|
||||||
// 2.2 更新支付单到 demo 订单
|
// 2.2 更新退款单到 demo 订单
|
||||||
payDemoOrderMapper.updateById(new PayDemoOrderDO().setId(id)
|
payDemoOrderMapper.updateById(new PayDemoOrderDO().setId(id)
|
||||||
.setPayRefundId(payRefundId).setRefundPrice(order.getPrice()));
|
.setPayRefundId(payRefundId).setRefundPrice(order.getPrice()));
|
||||||
}
|
}
|
||||||
|
@ -207,11 +212,57 @@ public class PayDemoOrderServiceImpl implements PayDemoOrderService {
|
||||||
if (!order.getPayed()) {
|
if (!order.getPayed()) {
|
||||||
throw exception(PAY_DEMO_ORDER_REFUND_FAIL_NOT_PAID);
|
throw exception(PAY_DEMO_ORDER_REFUND_FAIL_NOT_PAID);
|
||||||
}
|
}
|
||||||
// 校验是否已经发起退款
|
// 校验订单是否已退款
|
||||||
if (order.getPayRefundId() != null) {
|
if (order.getPayRefundId() != null) {
|
||||||
throw exception(PAY_DEMO_ORDER_REFUND_FAIL_REFUNDED);
|
throw exception(PAY_DEMO_ORDER_REFUND_FAIL_REFUNDED);
|
||||||
}
|
}
|
||||||
return order;
|
return order;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateDemoOrderRefunded(Long id, Long payRefundId) {
|
||||||
|
// 1. 校验并获得退款订单(可退款)
|
||||||
|
PayRefundRespDTO payRefund = validateDemoOrderCanRefunded(id, payRefundId);
|
||||||
|
// 2.2 更新退款单到 demo 订单
|
||||||
|
payDemoOrderMapper.updateById(new PayDemoOrderDO().setId(id)
|
||||||
|
.setRefundTime(payRefund.getSuccessTime()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private PayRefundRespDTO validateDemoOrderCanRefunded(Long id, Long payRefundId) {
|
||||||
|
// 1.1 校验示例订单
|
||||||
|
PayDemoOrderDO order = payDemoOrderMapper.selectById(id);
|
||||||
|
if (order == null) {
|
||||||
|
throw exception(PAY_DEMO_ORDER_NOT_FOUND);
|
||||||
|
}
|
||||||
|
// 1.2 校验退款订单匹配
|
||||||
|
if (Objects.equals(order.getPayOrderId(), payRefundId)) {
|
||||||
|
log.error("[validateDemoOrderCanRefunded][order({}) 退款单不匹配({}),请进行处理!order 数据是:{}]",
|
||||||
|
id, payRefundId, toJsonString(order));
|
||||||
|
throw exception(PAY_DEMO_ORDER_REFUND_FAIL_REFUND_ORDER_ID_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2.1 校验退款订单
|
||||||
|
PayRefundRespDTO payRefund = payRefundApi.getPayRefund(payRefundId);
|
||||||
|
if (payRefund == null) {
|
||||||
|
throw exception(PAY_DEMO_ORDER_REFUND_FAIL_REFUND_NOT_FOUND);
|
||||||
|
}
|
||||||
|
// 2.2
|
||||||
|
if (!PayRefundStatusEnum.isSuccess(payRefund.getStatus())) {
|
||||||
|
throw exception(PAY_DEMO_ORDER_REFUND_FAIL_REFUND_NOT_SUCCESS);
|
||||||
|
}
|
||||||
|
// 2.3 校验退款金额一致
|
||||||
|
if (notEqual(payRefund.getRefundAmount(), order.getPrice())) {
|
||||||
|
log.error("[validateDemoOrderCanRefunded][order({}) payRefund({}) 退款金额不匹配,请进行处理!order 数据是:{},payRefund 数据是:{}]",
|
||||||
|
id, payRefundId, toJsonString(order), toJsonString(payRefund));
|
||||||
|
throw exception(PAY_DEMO_ORDER_REFUND_FAIL_REFUND_PRICE_NOT_MATCH);
|
||||||
|
}
|
||||||
|
// 2.4 校验退款订单匹配(二次)
|
||||||
|
if (notEqual(payRefund.getMerchantOrderId(), id.toString())) {
|
||||||
|
log.error("[validateDemoOrderCanRefunded][order({}) 退款单不匹配({}),请进行处理!payRefund 数据是:{}]",
|
||||||
|
id, payRefundId, toJsonString(payRefund));
|
||||||
|
throw exception(PAY_DEMO_ORDER_REFUND_FAIL_REFUND_ORDER_ID_ERROR);
|
||||||
|
}
|
||||||
|
return payRefund;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,53 +0,0 @@
|
||||||
package cn.iocoder.yudao.module.pay.service.order.dto;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Builder;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
import lombok.experimental.Accessors;
|
|
||||||
|
|
||||||
import javax.validation.constraints.DecimalMin;
|
|
||||||
import javax.validation.constraints.NotEmpty;
|
|
||||||
import javax.validation.constraints.NotNull;
|
|
||||||
|
|
||||||
// TODO 芋艿:可能需要改造
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 退款申请单 Request DTO
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@Accessors(chain = true)
|
|
||||||
@Builder
|
|
||||||
@NoArgsConstructor
|
|
||||||
@AllArgsConstructor
|
|
||||||
public class PayRefundReqDTO {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 支付订单编号
|
|
||||||
*/
|
|
||||||
@NotNull(message = "支付订单编号不能为空")
|
|
||||||
private Long payOrderId;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 退款金额
|
|
||||||
*/
|
|
||||||
@NotNull(message = "退款金额不能为空")
|
|
||||||
@DecimalMin(value = "0", inclusive = false, message = "退款金额必须大于零")
|
|
||||||
private Integer amount;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 退款原因
|
|
||||||
*/
|
|
||||||
private String reason;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 商户退款订单号
|
|
||||||
*/
|
|
||||||
@NotEmpty(message = "商户退款订单号不能为空")
|
|
||||||
private String merchantRefundId;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 用户 IP
|
|
||||||
*/
|
|
||||||
private String userIp;
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
package cn.iocoder.yudao.module.pay.service.order.dto;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Builder;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
import lombok.experimental.Accessors;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 退款申请单 Response DTO
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@Accessors(chain = true)
|
|
||||||
@Builder
|
|
||||||
@NoArgsConstructor
|
|
||||||
@AllArgsConstructor
|
|
||||||
public class PayRefundRespDTO {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 支付退款单编号,自增
|
|
||||||
*/
|
|
||||||
private Long refundId;
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,12 +1,11 @@
|
||||||
package cn.iocoder.yudao.module.pay.service.refund;
|
package cn.iocoder.yudao.module.pay.service.refund;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.dto.PayNotifyDataDTO;
|
import cn.iocoder.yudao.framework.pay.core.client.dto.PayNotifyDataDTO;
|
||||||
|
import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO;
|
||||||
import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundExportReqVO;
|
import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundExportReqVO;
|
||||||
import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundPageReqVO;
|
import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundPageReqVO;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO;
|
import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO;
|
||||||
import cn.iocoder.yudao.module.pay.service.order.dto.PayRefundReqDTO;
|
|
||||||
import cn.iocoder.yudao.module.pay.service.order.dto.PayRefundRespDTO;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@ -42,12 +41,12 @@ public interface PayRefundService {
|
||||||
List<PayRefundDO> getRefundList(PayRefundExportReqVO exportReqVO);
|
List<PayRefundDO> getRefundList(PayRefundExportReqVO exportReqVO);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 提交退款申请
|
* 创建退款申请
|
||||||
*
|
*
|
||||||
* @param reqDTO 退款申请信息
|
* @param reqDTO 退款申请信息
|
||||||
* @return 退款申请返回信息
|
* @return 退款单号
|
||||||
*/
|
*/
|
||||||
PayRefundRespDTO submitRefundOrder(PayRefundReqDTO reqDTO);
|
Long createPayRefund(PayRefundCreateReqDTO reqDTO);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 渠道的退款通知
|
* 渠道的退款通知
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package cn.iocoder.yudao.module.pay.service.refund;
|
package cn.iocoder.yudao.module.pay.service.refund;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.RandomUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
|
import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.PayClient;
|
import cn.iocoder.yudao.framework.pay.core.client.PayClient;
|
||||||
|
@ -10,6 +11,7 @@ import cn.iocoder.yudao.framework.pay.core.client.dto.PayRefundNotifyDTO;
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.dto.PayRefundUnifiedReqDTO;
|
import cn.iocoder.yudao.framework.pay.core.client.dto.PayRefundUnifiedReqDTO;
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.dto.PayRefundUnifiedRespDTO;
|
import cn.iocoder.yudao.framework.pay.core.client.dto.PayRefundUnifiedRespDTO;
|
||||||
import cn.iocoder.yudao.framework.pay.core.enums.PayNotifyRefundStatusEnum;
|
import cn.iocoder.yudao.framework.pay.core.enums.PayNotifyRefundStatusEnum;
|
||||||
|
import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO;
|
||||||
import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundExportReqVO;
|
import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundExportReqVO;
|
||||||
import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundPageReqVO;
|
import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundPageReqVO;
|
||||||
import cn.iocoder.yudao.module.pay.dal.dataobject.merchant.PayAppDO;
|
import cn.iocoder.yudao.module.pay.dal.dataobject.merchant.PayAppDO;
|
||||||
|
@ -32,8 +34,6 @@ import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService;
|
||||||
import cn.iocoder.yudao.module.pay.service.notify.dto.PayNotifyTaskCreateReqDTO;
|
import cn.iocoder.yudao.module.pay.service.notify.dto.PayNotifyTaskCreateReqDTO;
|
||||||
import cn.iocoder.yudao.module.pay.service.order.PayOrderExtensionService;
|
import cn.iocoder.yudao.module.pay.service.order.PayOrderExtensionService;
|
||||||
import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
|
import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
|
||||||
import cn.iocoder.yudao.module.pay.service.order.dto.PayRefundReqDTO;
|
|
||||||
import cn.iocoder.yudao.module.pay.service.order.dto.PayRefundRespDTO;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
@ -90,9 +90,9 @@ public class PayRefundServiceImpl implements PayRefundService {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public PayRefundRespDTO submitRefundOrder(PayRefundReqDTO req) {
|
public Long createPayRefund(PayRefundCreateReqDTO reqDTO) {
|
||||||
// 获得 PayOrderDO
|
// 获得 PayOrderDO
|
||||||
PayOrderDO order = orderService.getOrder(req.getPayOrderId());
|
PayOrderDO order = orderService.getOrder(reqDTO.getPayOrderId());
|
||||||
// 校验订单是否存在
|
// 校验订单是否存在
|
||||||
if (Objects.isNull(order) ) {
|
if (Objects.isNull(order) ) {
|
||||||
throw ServiceExceptionUtil.exception(ErrorCodeConstants.PAY_ORDER_NOT_FOUND);
|
throw ServiceExceptionUtil.exception(ErrorCodeConstants.PAY_ORDER_NOT_FOUND);
|
||||||
|
@ -108,15 +108,19 @@ public class PayRefundServiceImpl implements PayRefundService {
|
||||||
throw ServiceExceptionUtil.exception(ErrorCodeConstants.PAY_CHANNEL_CLIENT_NOT_FOUND);
|
throw ServiceExceptionUtil.exception(ErrorCodeConstants.PAY_CHANNEL_CLIENT_NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO 芋艿:待实现
|
||||||
|
String merchantRefundId = RandomUtil.randomNumbers(16);
|
||||||
|
|
||||||
// 校验退款的条件
|
// 校验退款的条件
|
||||||
validatePayRefund(req, order);
|
validatePayRefund(reqDTO, order);
|
||||||
// 退款类型
|
// 退款类型
|
||||||
PayRefundTypeEnum refundType = PayRefundTypeEnum.SOME;
|
PayRefundTypeEnum refundType = PayRefundTypeEnum.SOME;
|
||||||
if (Objects.equals(req.getAmount(), order.getAmount())) {
|
if (Objects.equals(reqDTO.getAmount(), order.getAmount())) {
|
||||||
refundType = PayRefundTypeEnum.ALL;
|
refundType = PayRefundTypeEnum.ALL;
|
||||||
}
|
}
|
||||||
PayOrderExtensionDO orderExtensionDO = orderExtensionService.getOrderExtension(order.getSuccessExtensionId());
|
PayOrderExtensionDO orderExtensionDO = orderExtensionService.getOrderExtension(order.getSuccessExtensionId());
|
||||||
PayRefundDO payRefundDO = refundMapper.selectByTradeNoAndMerchantRefundNo(orderExtensionDO.getNo(), req.getMerchantRefundId());
|
PayRefundDO payRefundDO = refundMapper.selectByTradeNoAndMerchantRefundNo(orderExtensionDO.getNo(),
|
||||||
|
merchantRefundId); // TODO 芋艿:需要优化
|
||||||
if(Objects.nonNull(payRefundDO)){
|
if(Objects.nonNull(payRefundDO)){
|
||||||
// 退款订单已经提交过。
|
// 退款订单已经提交过。
|
||||||
//TODO 校验相同退款单的金额
|
//TODO 校验相同退款单的金额
|
||||||
|
@ -137,15 +141,15 @@ public class PayRefundServiceImpl implements PayRefundService {
|
||||||
.channelId(order.getChannelId())
|
.channelId(order.getChannelId())
|
||||||
.merchantId(order.getMerchantId())
|
.merchantId(order.getMerchantId())
|
||||||
.orderId(order.getId())
|
.orderId(order.getId())
|
||||||
.merchantRefundNo(req.getMerchantRefundId())
|
.merchantRefundNo(merchantRefundId) // TODO 芋艿:需要优化
|
||||||
.notifyUrl(app.getRefundNotifyUrl())
|
.notifyUrl(app.getRefundNotifyUrl())
|
||||||
.payAmount(order.getAmount())
|
.payAmount(order.getAmount())
|
||||||
.refundAmount(req.getAmount())
|
.refundAmount(reqDTO.getAmount())
|
||||||
.userIp(req.getUserIp())
|
.userIp(reqDTO.getUserIp())
|
||||||
.merchantOrderId(order.getMerchantOrderId())
|
.merchantOrderId(order.getMerchantOrderId())
|
||||||
.tradeNo(orderExtensionDO.getNo())
|
.tradeNo(orderExtensionDO.getNo())
|
||||||
.status(PayRefundStatusEnum.CREATE.getStatus())
|
.status(PayRefundStatusEnum.CREATE.getStatus())
|
||||||
.reason(req.getReason())
|
.reason(reqDTO.getReason())
|
||||||
.notifyStatus(PayOrderNotifyStatusEnum.NO.getStatus())
|
.notifyStatus(PayOrderNotifyStatusEnum.NO.getStatus())
|
||||||
.type(refundType.getStatus())
|
.type(refundType.getStatus())
|
||||||
.build();
|
.build();
|
||||||
|
@ -153,12 +157,12 @@ public class PayRefundServiceImpl implements PayRefundService {
|
||||||
}
|
}
|
||||||
// TODO @jason:搞到 convert 里。一些额外的自动,手动 set 下;
|
// TODO @jason:搞到 convert 里。一些额外的自动,手动 set 下;
|
||||||
PayRefundUnifiedReqDTO unifiedReqDTO = new PayRefundUnifiedReqDTO();
|
PayRefundUnifiedReqDTO unifiedReqDTO = new PayRefundUnifiedReqDTO();
|
||||||
unifiedReqDTO.setUserIp(req.getUserIp())
|
unifiedReqDTO.setUserIp(reqDTO.getUserIp())
|
||||||
.setAmount(req.getAmount())
|
.setAmount(reqDTO.getAmount())
|
||||||
.setChannelOrderNo(order.getChannelOrderNo())
|
.setChannelOrderNo(order.getChannelOrderNo())
|
||||||
.setPayTradeNo(orderExtensionDO.getNo())
|
.setPayTradeNo(orderExtensionDO.getNo())
|
||||||
.setMerchantRefundId(req.getMerchantRefundId())
|
.setMerchantRefundId(merchantRefundId) // TODO 芋艿:需要优化
|
||||||
.setReason(req.getReason());
|
.setReason(reqDTO.getReason());
|
||||||
// 向渠道发起退款申请
|
// 向渠道发起退款申请
|
||||||
PayCommonResult<PayRefundUnifiedRespDTO> refundUnifiedResult = client.unifiedRefund(unifiedReqDTO);
|
PayCommonResult<PayRefundUnifiedRespDTO> refundUnifiedResult = client.unifiedRefund(unifiedReqDTO);
|
||||||
// 检查是否失败,失败抛出业务异常。
|
// 检查是否失败,失败抛出业务异常。
|
||||||
|
@ -166,7 +170,7 @@ public class PayRefundServiceImpl implements PayRefundService {
|
||||||
// TODO @jason:可以先打个 warn log 哈;
|
// TODO @jason:可以先打个 warn log 哈;
|
||||||
refundUnifiedResult.checkError();
|
refundUnifiedResult.checkError();
|
||||||
// 成功在 退款回调中处理
|
// 成功在 退款回调中处理
|
||||||
return PayRefundRespDTO.builder().refundId(payRefundDO.getId()).build();
|
return payRefundDO.getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -235,10 +239,11 @@ public class PayRefundServiceImpl implements PayRefundService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 校验是否进行退款
|
* 校验是否进行退款
|
||||||
* @param req 退款申请信息
|
*
|
||||||
|
* @param reqDTO 退款申请信息
|
||||||
* @param order 原始支付订单信息
|
* @param order 原始支付订单信息
|
||||||
*/
|
*/
|
||||||
private void validatePayRefund(PayRefundReqDTO req, PayOrderDO order) {
|
private void validatePayRefund(PayRefundCreateReqDTO reqDTO, PayOrderDO order) {
|
||||||
// 校验状态,必须是支付状态
|
// 校验状态,必须是支付状态
|
||||||
if (!PayOrderStatusEnum.SUCCESS.getStatus().equals(order.getStatus())) {
|
if (!PayOrderStatusEnum.SUCCESS.getStatus().equals(order.getStatus())) {
|
||||||
throw ServiceExceptionUtil.exception(ErrorCodeConstants.PAY_ORDER_STATUS_IS_NOT_SUCCESS);
|
throw ServiceExceptionUtil.exception(ErrorCodeConstants.PAY_ORDER_STATUS_IS_NOT_SUCCESS);
|
||||||
|
@ -248,7 +253,7 @@ public class PayRefundServiceImpl implements PayRefundService {
|
||||||
throw ServiceExceptionUtil.exception(ErrorCodeConstants.PAY_REFUND_ALL_REFUNDED);
|
throw ServiceExceptionUtil.exception(ErrorCodeConstants.PAY_REFUND_ALL_REFUNDED);
|
||||||
}
|
}
|
||||||
// 校验金额 退款金额不能大于 原定的金额
|
// 校验金额 退款金额不能大于 原定的金额
|
||||||
if (req.getAmount() + order.getRefundAmount() > order.getAmount()){
|
if (reqDTO.getAmount() + order.getRefundAmount() > order.getAmount()){
|
||||||
throw ServiceExceptionUtil.exception(ErrorCodeConstants.PAY_REFUND_AMOUNT_EXCEED);
|
throw ServiceExceptionUtil.exception(ErrorCodeConstants.PAY_REFUND_AMOUNT_EXCEED);
|
||||||
}
|
}
|
||||||
// 校验渠道订单号
|
// 校验渠道订单号
|
||||||
|
|
|
@ -18,6 +18,7 @@ public class PaySeqUtils {
|
||||||
|
|
||||||
private static final AtomicLong MER_ORDER_NO_SEQ = new AtomicLong(0L);
|
private static final AtomicLong MER_ORDER_NO_SEQ = new AtomicLong(0L);
|
||||||
|
|
||||||
|
// TODO 芋艿:需要看看
|
||||||
/**
|
/**
|
||||||
* 生成商户退款单号,用于测试,应该由商户系统生成
|
* 生成商户退款单号,用于测试,应该由商户系统生成
|
||||||
* @return 商户退款单
|
* @return 商户退款单
|
||||||
|
@ -28,6 +29,8 @@ public class PaySeqUtils {
|
||||||
(int) MER_REFUND_NO_SEQ.getAndIncrement() % 10000);
|
(int) MER_REFUND_NO_SEQ.getAndIncrement() % 10000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO 芋艿:需要看看
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成退款请求号
|
* 生成退款请求号
|
||||||
* @return 退款请求号
|
* @return 退款请求号
|
||||||
|
|
|
@ -206,7 +206,7 @@ export default {
|
||||||
return refundDemoOrder(id);
|
return refundDemoOrder(id);
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
this.getList();
|
this.getList();
|
||||||
this.$modal.msgSuccess("退款成功");
|
this.$modal.msgSuccess("发起退款成功!");
|
||||||
}).catch(() => {});
|
}).catch(() => {});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue