mirror of
				https://gitee.com/hhyykk/ipms-sjy.git
				synced 2025-11-04 04:08:43 +08:00 
			
		
		
		
	!1041 支付应用,增加 appKey 标识,用于不同接入方的标识
* feat[yudao-module-pay]: 更新新增和更新支付应用时校验逻辑 * fix[yudao-module-trade]: 为支付应用标识提供缺省值 * fix[yudao-module-pay]: appKey注释应用编码更新为应用标识 * feat[yudao-module-pay]: 为支付应用新增支付编码属性
This commit is contained in:
		
							
								
								
									
										18
									
								
								pom.xml
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								pom.xml
									
									
									
									
									
								
							@@ -15,15 +15,15 @@
 | 
				
			|||||||
        <!-- 各种 module 拓展 -->
 | 
					        <!-- 各种 module 拓展 -->
 | 
				
			||||||
        <module>yudao-module-system</module>
 | 
					        <module>yudao-module-system</module>
 | 
				
			||||||
        <module>yudao-module-infra</module>
 | 
					        <module>yudao-module-infra</module>
 | 
				
			||||||
<!--        <module>yudao-module-member</module>-->
 | 
					        <module>yudao-module-member</module>
 | 
				
			||||||
<!--        <module>yudao-module-bpm</module>-->
 | 
					        <module>yudao-module-bpm</module>
 | 
				
			||||||
<!--        <module>yudao-module-report</module>-->
 | 
					        <module>yudao-module-report</module>
 | 
				
			||||||
<!--        <module>yudao-module-mp</module>-->
 | 
					        <module>yudao-module-mp</module>
 | 
				
			||||||
<!--        <module>yudao-module-pay</module>-->
 | 
					        <module>yudao-module-pay</module>
 | 
				
			||||||
<!--        <module>yudao-module-mall</module>-->
 | 
					        <module>yudao-module-mall</module>
 | 
				
			||||||
<!--        <module>yudao-module-crm</module>-->
 | 
					        <module>yudao-module-crm</module>
 | 
				
			||||||
<!--        <module>yudao-module-erp</module>-->
 | 
					        <module>yudao-module-erp</module>
 | 
				
			||||||
<!--        <module>yudao-module-ai</module>-->
 | 
					        <module>yudao-module-ai</module>
 | 
				
			||||||
    </modules>
 | 
					    </modules>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <name>${project.artifactId}</name>
 | 
					    <name>${project.artifactId}</name>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -101,7 +101,7 @@ public interface TradeOrderConvert {
 | 
				
			|||||||
    default PayOrderCreateReqDTO convert(TradeOrderDO order, List<TradeOrderItemDO> orderItems,
 | 
					    default PayOrderCreateReqDTO convert(TradeOrderDO order, List<TradeOrderItemDO> orderItems,
 | 
				
			||||||
                                         TradeOrderProperties orderProperties) {
 | 
					                                         TradeOrderProperties orderProperties) {
 | 
				
			||||||
        PayOrderCreateReqDTO createReqDTO = new PayOrderCreateReqDTO()
 | 
					        PayOrderCreateReqDTO createReqDTO = new PayOrderCreateReqDTO()
 | 
				
			||||||
                .setAppId(orderProperties.getAppId()).setUserIp(order.getUserIp());
 | 
					                .setAppKey(orderProperties.getAppKey()).setUserIp(order.getUserIp());
 | 
				
			||||||
        // 商户相关字段
 | 
					        // 商户相关字段
 | 
				
			||||||
        createReqDTO.setMerchantOrderId(String.valueOf(order.getId()));
 | 
					        createReqDTO.setMerchantOrderId(String.valueOf(order.getId()));
 | 
				
			||||||
        String subject = orderItems.get(0).getSpuName();
 | 
					        String subject = orderItems.get(0).getSpuName();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,6 +5,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
 | 
				
			|||||||
import org.springframework.validation.annotation.Validated;
 | 
					import org.springframework.validation.annotation.Validated;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import jakarta.validation.constraints.NotNull;
 | 
					import jakarta.validation.constraints.NotNull;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.time.Duration;
 | 
					import java.time.Duration;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@@ -19,10 +20,16 @@ import java.time.Duration;
 | 
				
			|||||||
public class TradeOrderProperties {
 | 
					public class TradeOrderProperties {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * 应用编号
 | 
					     * 默认应用标识
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    @NotNull(message = "应用编号不能为空")
 | 
					    private static final String APP_KEY_DEFAULT = "mall";
 | 
				
			||||||
    private Long appId;
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 应用标识,用于区分不同的应用程序
 | 
				
			||||||
 | 
					     * 通过注解@NotNull确保应用标识不能为空
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    @NotNull(message = "应用标识不能为空")
 | 
				
			||||||
 | 
					    private String appKey = APP_KEY_DEFAULT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * 支付超时时间
 | 
					     * 支付超时时间
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -99,7 +99,7 @@ public class TradeOrderUpdateServiceTest extends BaseDbUnitTest {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    @BeforeEach
 | 
					    @BeforeEach
 | 
				
			||||||
    public void setUp() {
 | 
					    public void setUp() {
 | 
				
			||||||
        when(tradeOrderProperties.getAppId()).thenReturn(888L);
 | 
					        when(tradeOrderProperties.getAppKey()).thenReturn("demo");
 | 
				
			||||||
        when(tradeOrderProperties.getPayExpireTime()).thenReturn(Duration.ofDays(1));
 | 
					        when(tradeOrderProperties.getPayExpireTime()).thenReturn(Duration.ofDays(1));
 | 
				
			||||||
        when(tradeNoRedisDAO.generate(anyString())).thenReturn(IdUtil.randomUUID());
 | 
					        when(tradeNoRedisDAO.generate(anyString())).thenReturn(IdUtil.randomUUID());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,11 +1,11 @@
 | 
				
			|||||||
package cn.iocoder.yudao.module.pay.api.order.dto;
 | 
					package cn.iocoder.yudao.module.pay.api.order.dto;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import lombok.Data;
 | 
					 | 
				
			||||||
import org.hibernate.validator.constraints.Length;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import jakarta.validation.constraints.DecimalMin;
 | 
					import jakarta.validation.constraints.DecimalMin;
 | 
				
			||||||
import jakarta.validation.constraints.NotEmpty;
 | 
					import jakarta.validation.constraints.NotEmpty;
 | 
				
			||||||
import jakarta.validation.constraints.NotNull;
 | 
					import jakarta.validation.constraints.NotNull;
 | 
				
			||||||
 | 
					import lombok.Data;
 | 
				
			||||||
 | 
					import org.hibernate.validator.constraints.Length;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.io.Serializable;
 | 
					import java.io.Serializable;
 | 
				
			||||||
import java.time.LocalDateTime;
 | 
					import java.time.LocalDateTime;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -18,10 +18,10 @@ public class PayOrderCreateReqDTO implements Serializable {
 | 
				
			|||||||
    public static final int SUBJECT_MAX_LENGTH = 32;
 | 
					    public static final int SUBJECT_MAX_LENGTH = 32;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * 应用编号
 | 
					     * 应用标识
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    @NotNull(message = "应用编号不能为空")
 | 
					    @NotNull(message = "应用标识不能为空")
 | 
				
			||||||
    private Long appId;
 | 
					    private String appKey;
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * 用户 IP
 | 
					     * 用户 IP
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,11 +1,10 @@
 | 
				
			|||||||
package cn.iocoder.yudao.module.pay.api.refund.dto;
 | 
					package cn.iocoder.yudao.module.pay.api.refund.dto;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import lombok.Data;
 | 
					 | 
				
			||||||
import org.hibernate.validator.constraints.Length;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import jakarta.validation.constraints.Min;
 | 
					import jakarta.validation.constraints.Min;
 | 
				
			||||||
import jakarta.validation.constraints.NotEmpty;
 | 
					import jakarta.validation.constraints.NotEmpty;
 | 
				
			||||||
import jakarta.validation.constraints.NotNull;
 | 
					import jakarta.validation.constraints.NotNull;
 | 
				
			||||||
 | 
					import lombok.Data;
 | 
				
			||||||
 | 
					import org.hibernate.validator.constraints.Length;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * 退款单创建 Request DTO
 | 
					 * 退款单创建 Request DTO
 | 
				
			||||||
@@ -16,10 +15,10 @@ import jakarta.validation.constraints.NotNull;
 | 
				
			|||||||
public class PayRefundCreateReqDTO {
 | 
					public class PayRefundCreateReqDTO {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * 应用编号
 | 
					     * 应用标识
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    @NotNull(message = "应用编号不能为空")
 | 
					    @NotNull(message = "应用标识不能为空")
 | 
				
			||||||
    private Long appId;
 | 
					    private String appKey;
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * 用户 IP
 | 
					     * 用户 IP
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,12 +2,12 @@ package cn.iocoder.yudao.module.pay.api.transfer.dto;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import cn.iocoder.yudao.framework.common.validation.InEnum;
 | 
					import cn.iocoder.yudao.framework.common.validation.InEnum;
 | 
				
			||||||
import cn.iocoder.yudao.module.pay.enums.transfer.PayTransferTypeEnum;
 | 
					import cn.iocoder.yudao.module.pay.enums.transfer.PayTransferTypeEnum;
 | 
				
			||||||
import lombok.Data;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import jakarta.validation.constraints.Min;
 | 
					import jakarta.validation.constraints.Min;
 | 
				
			||||||
import jakarta.validation.constraints.NotBlank;
 | 
					import jakarta.validation.constraints.NotBlank;
 | 
				
			||||||
import jakarta.validation.constraints.NotEmpty;
 | 
					import jakarta.validation.constraints.NotEmpty;
 | 
				
			||||||
import jakarta.validation.constraints.NotNull;
 | 
					import jakarta.validation.constraints.NotNull;
 | 
				
			||||||
 | 
					import lombok.Data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.Map;
 | 
					import java.util.Map;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@@ -19,10 +19,10 @@ import java.util.Map;
 | 
				
			|||||||
public class PayTransferCreateReqDTO {
 | 
					public class PayTransferCreateReqDTO {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * 应用编号
 | 
					     * 应用标识
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    @NotNull(message = "应用编号不能为空")
 | 
					    @NotNull(message = "应用标识不能为空")
 | 
				
			||||||
    private Long appId;
 | 
					    private String appKey;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @NotEmpty(message = "转账渠道不能为空")
 | 
					    @NotEmpty(message = "转账渠道不能为空")
 | 
				
			||||||
    private String channelCode;
 | 
					    private String channelCode;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,6 +14,7 @@ public interface ErrorCodeConstants {
 | 
				
			|||||||
    ErrorCode APP_IS_DISABLE = new ErrorCode(1_007_000_002, "App 已经被禁用");
 | 
					    ErrorCode APP_IS_DISABLE = new ErrorCode(1_007_000_002, "App 已经被禁用");
 | 
				
			||||||
    ErrorCode APP_EXIST_ORDER_CANT_DELETE =  new ErrorCode(1_007_000_003, "支付应用存在支付订单,无法删除");
 | 
					    ErrorCode APP_EXIST_ORDER_CANT_DELETE =  new ErrorCode(1_007_000_003, "支付应用存在支付订单,无法删除");
 | 
				
			||||||
    ErrorCode APP_EXIST_REFUND_CANT_DELETE =  new ErrorCode(1_007_000_004, "支付应用存在退款订单,无法删除");
 | 
					    ErrorCode APP_EXIST_REFUND_CANT_DELETE =  new ErrorCode(1_007_000_004, "支付应用存在退款订单,无法删除");
 | 
				
			||||||
 | 
					    ErrorCode APP_KEY_EXISTS = new ErrorCode(1_007_000_005, "支付应用标识已经存在");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // ========== CHANNEL 模块 1-007-001-000 ==========
 | 
					    // ========== CHANNEL 模块 1-007-001-000 ==========
 | 
				
			||||||
    ErrorCode CHANNEL_NOT_FOUND = new ErrorCode(1_007_001_000, "支付渠道的配置不存在");
 | 
					    ErrorCode CHANNEL_NOT_FOUND = new ErrorCode(1_007_001_000, "支付渠道的配置不存在");
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,6 @@
 | 
				
			|||||||
package cn.iocoder.yudao.module.pay.controller.admin.app.vo;
 | 
					package cn.iocoder.yudao.module.pay.controller.admin.app.vo;
 | 
				
			||||||
import io.swagger.v3.oas.annotations.media.Schema;
 | 
					import io.swagger.v3.oas.annotations.media.Schema;
 | 
				
			||||||
 | 
					import jakarta.validation.constraints.NotNull;
 | 
				
			||||||
import lombok.*;
 | 
					import lombok.*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Schema(description = "管理后台 - 支付应用信息创建 Request VO")
 | 
					@Schema(description = "管理后台 - 支付应用信息创建 Request VO")
 | 
				
			||||||
@@ -8,4 +9,8 @@ import lombok.*;
 | 
				
			|||||||
@ToString(callSuper = true)
 | 
					@ToString(callSuper = true)
 | 
				
			||||||
public class PayAppCreateReqVO extends PayAppBaseVO {
 | 
					public class PayAppCreateReqVO extends PayAppBaseVO {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Schema(description = "应用标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao")
 | 
				
			||||||
 | 
					    @NotNull(message = "应用标识不能为空")
 | 
				
			||||||
 | 
					    private String appKey;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,6 +17,9 @@ public class PayAppPageItemRespVO extends PayAppBaseVO {
 | 
				
			|||||||
    @Schema(description = "应用编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
 | 
					    @Schema(description = "应用编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
 | 
				
			||||||
    private Long id;
 | 
					    private Long id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Schema(description = "应用标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao")
 | 
				
			||||||
 | 
					    private String appKey;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
 | 
					    @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
 | 
				
			||||||
    private LocalDateTime createTime;
 | 
					    private LocalDateTime createTime;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,6 +20,9 @@ public class PayAppPageReqVO extends PageParam {
 | 
				
			|||||||
    @Schema(description = "应用名", example = "小豆")
 | 
					    @Schema(description = "应用名", example = "小豆")
 | 
				
			||||||
    private String name;
 | 
					    private String name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Schema(description = "应用标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao")
 | 
				
			||||||
 | 
					    private String appKey;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Schema(description = "开启状态", example = "0")
 | 
					    @Schema(description = "开启状态", example = "0")
 | 
				
			||||||
    private Integer status;
 | 
					    private Integer status;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,9 @@
 | 
				
			|||||||
package cn.iocoder.yudao.module.pay.controller.admin.app.vo;
 | 
					package cn.iocoder.yudao.module.pay.controller.admin.app.vo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import io.swagger.v3.oas.annotations.media.Schema;
 | 
					import io.swagger.v3.oas.annotations.media.Schema;
 | 
				
			||||||
import lombok.*;
 | 
					import lombok.Data;
 | 
				
			||||||
 | 
					import lombok.EqualsAndHashCode;
 | 
				
			||||||
 | 
					import lombok.ToString;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.time.LocalDateTime;
 | 
					import java.time.LocalDateTime;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -13,6 +16,9 @@ public class PayAppRespVO extends PayAppBaseVO {
 | 
				
			|||||||
    @Schema(description = "应用编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
 | 
					    @Schema(description = "应用编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
 | 
				
			||||||
    private Long id;
 | 
					    private Long id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Schema(description = "应用标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao")
 | 
				
			||||||
 | 
					    private String appKey;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
 | 
					    @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
 | 
				
			||||||
    private LocalDateTime createTime;
 | 
					    private LocalDateTime createTime;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,5 @@
 | 
				
			|||||||
package cn.iocoder.yudao.module.pay.controller.admin.app.vo;
 | 
					package cn.iocoder.yudao.module.pay.controller.admin.app.vo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import io.swagger.v3.oas.annotations.media.Schema;
 | 
					import io.swagger.v3.oas.annotations.media.Schema;
 | 
				
			||||||
import lombok.*;
 | 
					import lombok.*;
 | 
				
			||||||
import jakarta.validation.constraints.*;
 | 
					import jakarta.validation.constraints.*;
 | 
				
			||||||
@@ -13,4 +14,8 @@ public class PayAppUpdateReqVO extends PayAppBaseVO {
 | 
				
			|||||||
    @NotNull(message = "应用编号不能为空")
 | 
					    @NotNull(message = "应用编号不能为空")
 | 
				
			||||||
    private Long id;
 | 
					    private Long id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Schema(description = "应用标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao")
 | 
				
			||||||
 | 
					    @NotNull(message = "应用标识不能为空")
 | 
				
			||||||
 | 
					    private String appKey;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -31,6 +31,10 @@ public class PayAppDO extends BaseDO {
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    @TableId
 | 
					    @TableId
 | 
				
			||||||
    private Long id;
 | 
					    private Long id;
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 应用标识
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private String appKey;
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * 应用名
 | 
					     * 应用名
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.pay.dal.mysql.app;
 | 
				
			|||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
 | 
					import cn.iocoder.yudao.framework.common.pojo.PageResult;
 | 
				
			||||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
 | 
					import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
 | 
				
			||||||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
 | 
					import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
 | 
				
			||||||
import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
 | 
					 | 
				
			||||||
import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppPageReqVO;
 | 
					import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppPageReqVO;
 | 
				
			||||||
import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
 | 
					import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
 | 
				
			||||||
import org.apache.ibatis.annotations.Mapper;
 | 
					import org.apache.ibatis.annotations.Mapper;
 | 
				
			||||||
@@ -14,9 +13,14 @@ public interface PayAppMapper extends BaseMapperX<PayAppDO> {
 | 
				
			|||||||
    default PageResult<PayAppDO> selectPage(PayAppPageReqVO reqVO) {
 | 
					    default PageResult<PayAppDO> selectPage(PayAppPageReqVO reqVO) {
 | 
				
			||||||
        return selectPage(reqVO, new LambdaQueryWrapperX<PayAppDO>()
 | 
					        return selectPage(reqVO, new LambdaQueryWrapperX<PayAppDO>()
 | 
				
			||||||
                .likeIfPresent(PayAppDO::getName, reqVO.getName())
 | 
					                .likeIfPresent(PayAppDO::getName, reqVO.getName())
 | 
				
			||||||
 | 
					                .likeIfPresent(PayAppDO::getAppKey, reqVO.getAppKey())
 | 
				
			||||||
                .eqIfPresent(PayAppDO::getStatus, reqVO.getStatus())
 | 
					                .eqIfPresent(PayAppDO::getStatus, reqVO.getStatus())
 | 
				
			||||||
                .betweenIfPresent(PayAppDO::getCreateTime, reqVO.getCreateTime())
 | 
					                .betweenIfPresent(PayAppDO::getCreateTime, reqVO.getCreateTime())
 | 
				
			||||||
                .orderByDesc(PayAppDO::getId));
 | 
					                .orderByDesc(PayAppDO::getId));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    default PayAppDO selectByAppKey(String appKey) {
 | 
				
			||||||
 | 
					        return selectOne(PayAppDO::getAppKey, appKey);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,8 +7,8 @@ import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppCreateReqVO;
 | 
				
			|||||||
import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppPageReqVO;
 | 
					import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppPageReqVO;
 | 
				
			||||||
import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppUpdateReqVO;
 | 
					import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppUpdateReqVO;
 | 
				
			||||||
import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
 | 
					import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
 | 
				
			||||||
 | 
					 | 
				
			||||||
import jakarta.validation.Valid;
 | 
					import jakarta.validation.Valid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.Collection;
 | 
					import java.util.Collection;
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
import java.util.Map;
 | 
					import java.util.Map;
 | 
				
			||||||
@@ -88,13 +88,13 @@ public interface PayAppService {
 | 
				
			|||||||
     * @return 商户 Map
 | 
					     * @return 商户 Map
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    default Map<Long, PayAppDO> getAppMap(Collection<Long> ids) {
 | 
					    default Map<Long, PayAppDO> getAppMap(Collection<Long> ids) {
 | 
				
			||||||
        List<PayAppDO> list =  getAppList(ids);
 | 
					        List<PayAppDO> list = getAppList(ids);
 | 
				
			||||||
        return CollectionUtils.convertMap(list, PayAppDO::getId);
 | 
					        return CollectionUtils.convertMap(list, PayAppDO::getId);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * 支付应用的合法性
 | 
					     * 支付应用的合法性
 | 
				
			||||||
     *
 | 
					     * <p>
 | 
				
			||||||
     * 如果不合法,抛出 {@link ServiceException} 业务异常
 | 
					     * 如果不合法,抛出 {@link ServiceException} 业务异常
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
     * @param id 应用编号
 | 
					     * @param id 应用编号
 | 
				
			||||||
@@ -102,4 +102,14 @@ public interface PayAppService {
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    PayAppDO validPayApp(Long id);
 | 
					    PayAppDO validPayApp(Long id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 支付应用的合法性
 | 
				
			||||||
 | 
					     * <p>
 | 
				
			||||||
 | 
					     * 如果不合法,抛出 {@link ServiceException} 业务异常
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param appKey 应用标识
 | 
				
			||||||
 | 
					     * @return 应用
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    PayAppDO validPayApp(String appKey);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,9 @@
 | 
				
			|||||||
package cn.iocoder.yudao.module.pay.service.app;
 | 
					package cn.iocoder.yudao.module.pay.service.app;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import cn.hutool.core.util.StrUtil;
 | 
				
			||||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
 | 
					import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
 | 
				
			||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
 | 
					import cn.iocoder.yudao.framework.common.pojo.PageResult;
 | 
				
			||||||
 | 
					import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
 | 
				
			||||||
import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppCreateReqVO;
 | 
					import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppCreateReqVO;
 | 
				
			||||||
import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppPageReqVO;
 | 
					import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppPageReqVO;
 | 
				
			||||||
import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppUpdateReqVO;
 | 
					import cn.iocoder.yudao.module.pay.controller.admin.app.vo.PayAppUpdateReqVO;
 | 
				
			||||||
@@ -11,13 +13,14 @@ import cn.iocoder.yudao.module.pay.dal.mysql.app.PayAppMapper;
 | 
				
			|||||||
import cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants;
 | 
					import cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants;
 | 
				
			||||||
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.refund.PayRefundService;
 | 
					import cn.iocoder.yudao.module.pay.service.refund.PayRefundService;
 | 
				
			||||||
 | 
					import jakarta.annotation.Resource;
 | 
				
			||||||
import org.springframework.context.annotation.Lazy;
 | 
					import org.springframework.context.annotation.Lazy;
 | 
				
			||||||
import org.springframework.stereotype.Service;
 | 
					import org.springframework.stereotype.Service;
 | 
				
			||||||
import org.springframework.validation.annotation.Validated;
 | 
					import org.springframework.validation.annotation.Validated;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import jakarta.annotation.Resource;
 | 
					 | 
				
			||||||
import java.util.Collection;
 | 
					import java.util.Collection;
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					import java.util.Objects;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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.module.pay.enums.ErrorCodeConstants.*;
 | 
					import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*;
 | 
				
			||||||
@@ -43,6 +46,8 @@ public class PayAppServiceImpl implements PayAppService {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public Long createApp(PayAppCreateReqVO createReqVO) {
 | 
					    public Long createApp(PayAppCreateReqVO createReqVO) {
 | 
				
			||||||
 | 
					        // 验证appKey是否重复
 | 
				
			||||||
 | 
					        validateAppKeyDuplicate(null, createReqVO.getAppKey());
 | 
				
			||||||
        // 插入
 | 
					        // 插入
 | 
				
			||||||
        PayAppDO app = PayAppConvert.INSTANCE.convert(createReqVO);
 | 
					        PayAppDO app = PayAppConvert.INSTANCE.convert(createReqVO);
 | 
				
			||||||
        appMapper.insert(app);
 | 
					        appMapper.insert(app);
 | 
				
			||||||
@@ -54,6 +59,8 @@ public class PayAppServiceImpl implements PayAppService {
 | 
				
			|||||||
    public void updateApp(PayAppUpdateReqVO updateReqVO) {
 | 
					    public void updateApp(PayAppUpdateReqVO updateReqVO) {
 | 
				
			||||||
        // 校验存在
 | 
					        // 校验存在
 | 
				
			||||||
        validateAppExists(updateReqVO.getId());
 | 
					        validateAppExists(updateReqVO.getId());
 | 
				
			||||||
 | 
					        // 验证appKey是否重复
 | 
				
			||||||
 | 
					        validateAppKeyDuplicate(updateReqVO.getId(), updateReqVO.getAppKey());
 | 
				
			||||||
        // 更新
 | 
					        // 更新
 | 
				
			||||||
        PayAppDO updateObj = PayAppConvert.INSTANCE.convert(updateReqVO);
 | 
					        PayAppDO updateObj = PayAppConvert.INSTANCE.convert(updateReqVO);
 | 
				
			||||||
        appMapper.updateById(updateObj);
 | 
					        appMapper.updateById(updateObj);
 | 
				
			||||||
@@ -101,7 +108,7 @@ public class PayAppServiceImpl implements PayAppService {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public List<PayAppDO> getAppList() {
 | 
					    public List<PayAppDO> getAppList() {
 | 
				
			||||||
         return appMapper.selectList();
 | 
					        return appMapper.selectList();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
@@ -110,8 +117,28 @@ public class PayAppServiceImpl implements PayAppService {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public PayAppDO validPayApp(Long id) {
 | 
					    public PayAppDO validPayApp(Long appId) {
 | 
				
			||||||
        PayAppDO app = appMapper.selectById(id);
 | 
					        PayAppDO app = appMapper.selectById(appId);
 | 
				
			||||||
 | 
					        // 校验支付应用数据是否存在以及可用
 | 
				
			||||||
 | 
					        return validatePayAppDO(app);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public PayAppDO validPayApp(String appKey) {
 | 
				
			||||||
 | 
					        PayAppDO app = appMapper.selectByAppKey(appKey);
 | 
				
			||||||
 | 
					        // 校验支付应用数据是否存在以及可用
 | 
				
			||||||
 | 
					        return validatePayAppDO(app);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 校验支付应用实体的有效性
 | 
				
			||||||
 | 
					     * 主要包括存在性检查和禁用状态检查
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param app 待校验的支付应用实体
 | 
				
			||||||
 | 
					     * @return 校验通过的支付应用实体
 | 
				
			||||||
 | 
					     * @throws IllegalArgumentException 如果支付应用实体不存在或已被禁用
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private PayAppDO validatePayAppDO(PayAppDO app) {
 | 
				
			||||||
        // 校验是否存在
 | 
					        // 校验是否存在
 | 
				
			||||||
        if (app == null) {
 | 
					        if (app == null) {
 | 
				
			||||||
            throw exception(ErrorCodeConstants.APP_NOT_FOUND);
 | 
					            throw exception(ErrorCodeConstants.APP_NOT_FOUND);
 | 
				
			||||||
@@ -123,4 +150,32 @@ public class PayAppServiceImpl implements PayAppService {
 | 
				
			|||||||
        return app;
 | 
					        return app;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 校验应用密钥是否重复
 | 
				
			||||||
 | 
					     * 在新增或更新支付应用时,确保应用密钥(appKey)的唯一性
 | 
				
			||||||
 | 
					     * 如果是在新增情况下,检查数据库中是否已存在相同的appKey
 | 
				
			||||||
 | 
					     * 如果是在更新情况下,检查数据库中是否存在除当前应用外的其他应用使用了相同的appKey
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param payAppId  支付应用的ID,更新时使用,新增时可能为null
 | 
				
			||||||
 | 
					     * @param payAppKey 支付应用的密钥,用于校验是否重复
 | 
				
			||||||
 | 
					     * @throws RuntimeException 如果发现appKey重复,抛出运行时异常
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private void validateAppKeyDuplicate(Long payAppId, String payAppKey) {
 | 
				
			||||||
 | 
					        // 新增时,校验appKey是否重复
 | 
				
			||||||
 | 
					        if (Objects.isNull(payAppId) && StrUtil.isNotBlank(payAppKey)) {
 | 
				
			||||||
 | 
					            if (appMapper.selectCount(PayAppDO::getAppKey, payAppKey) > 0) {
 | 
				
			||||||
 | 
					                throw exception(APP_KEY_EXISTS);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            // 更新时,校验appKey是否重复
 | 
				
			||||||
 | 
					        } else if (Objects.nonNull(payAppId) && StrUtil.isNotBlank(payAppKey)) {
 | 
				
			||||||
 | 
					            LambdaQueryWrapperX<PayAppDO> queryWrapper = new LambdaQueryWrapperX<>();
 | 
				
			||||||
 | 
					            queryWrapper.eq(PayAppDO::getAppKey, payAppKey)
 | 
				
			||||||
 | 
					                    .ne(PayAppDO::getId, payAppId);
 | 
				
			||||||
 | 
					            if (appMapper.selectCount(queryWrapper) > 0) {
 | 
				
			||||||
 | 
					                throw exception(APP_KEY_EXISTS);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -47,7 +47,7 @@ public class PayDemoOrderServiceImpl implements PayDemoOrderService {
 | 
				
			|||||||
     *
 | 
					     *
 | 
				
			||||||
     * 从 [支付管理 -> 应用信息] 里添加
 | 
					     * 从 [支付管理 -> 应用信息] 里添加
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    private static final Long PAY_APP_ID = 7L;
 | 
					    private static final String PAY_APP_KEY = "demo";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * 商品信息 Map
 | 
					     * 商品信息 Map
 | 
				
			||||||
@@ -88,7 +88,7 @@ public class PayDemoOrderServiceImpl implements PayDemoOrderService {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        // 2.1 创建支付单
 | 
					        // 2.1 创建支付单
 | 
				
			||||||
        Long payOrderId = payOrderApi.createOrder(new PayOrderCreateReqDTO()
 | 
					        Long payOrderId = payOrderApi.createOrder(new PayOrderCreateReqDTO()
 | 
				
			||||||
                .setAppId(PAY_APP_ID).setUserIp(getClientIP()) // 支付应用
 | 
					                .setAppKey(PAY_APP_KEY).setUserIp(getClientIP()) // 支付应用
 | 
				
			||||||
                .setMerchantOrderId(demoOrder.getId().toString()) // 业务的订单编号
 | 
					                .setMerchantOrderId(demoOrder.getId().toString()) // 业务的订单编号
 | 
				
			||||||
                .setSubject(spuName).setBody("").setPrice(price) // 价格信息
 | 
					                .setSubject(spuName).setBody("").setPrice(price) // 价格信息
 | 
				
			||||||
                .setExpireTime(addTime(Duration.ofHours(2L)))); // 支付的过期时间
 | 
					                .setExpireTime(addTime(Duration.ofHours(2L)))); // 支付的过期时间
 | 
				
			||||||
@@ -190,7 +190,7 @@ public class PayDemoOrderServiceImpl implements PayDemoOrderService {
 | 
				
			|||||||
        String refundId = order.getId() + "-refund";
 | 
					        String refundId = order.getId() + "-refund";
 | 
				
			||||||
        // 2.2 创建退款单
 | 
					        // 2.2 创建退款单
 | 
				
			||||||
        Long payRefundId = payRefundApi.createRefund(new PayRefundCreateReqDTO()
 | 
					        Long payRefundId = payRefundApi.createRefund(new PayRefundCreateReqDTO()
 | 
				
			||||||
                .setAppId(PAY_APP_ID).setUserIp(getClientIP()) // 支付应用
 | 
					                .setAppKey(PAY_APP_KEY).setUserIp(getClientIP()) // 支付应用
 | 
				
			||||||
                .setMerchantOrderId(String.valueOf(order.getId())) // 支付单号
 | 
					                .setMerchantOrderId(String.valueOf(order.getId())) // 支付单号
 | 
				
			||||||
                .setMerchantRefundId(refundId)
 | 
					                .setMerchantRefundId(refundId)
 | 
				
			||||||
                .setReason("想退钱").setPrice(order.getPrice()));// 价格信息
 | 
					                .setReason("想退钱").setPrice(order.getPrice()));// 价格信息
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -111,11 +111,11 @@ public class PayOrderServiceImpl implements PayOrderService {
 | 
				
			|||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public Long createOrder(PayOrderCreateReqDTO reqDTO) {
 | 
					    public Long createOrder(PayOrderCreateReqDTO reqDTO) {
 | 
				
			||||||
        // 校验 App
 | 
					        // 校验 App
 | 
				
			||||||
        PayAppDO app = appService.validPayApp(reqDTO.getAppId());
 | 
					        PayAppDO app = appService.validPayApp(reqDTO.getAppKey());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // 查询对应的支付交易单是否已经存在。如果是,则直接返回
 | 
					        // 查询对应的支付交易单是否已经存在。如果是,则直接返回
 | 
				
			||||||
        PayOrderDO order = orderMapper.selectByAppIdAndMerchantOrderId(
 | 
					        PayOrderDO order = orderMapper.selectByAppIdAndMerchantOrderId(
 | 
				
			||||||
                reqDTO.getAppId(), reqDTO.getMerchantOrderId());
 | 
					                app.getId(), reqDTO.getMerchantOrderId());
 | 
				
			||||||
        if (order != null) {
 | 
					        if (order != null) {
 | 
				
			||||||
            log.warn("[createOrder][appId({}) merchantOrderId({}) 已经存在对应的支付单({})]", order.getAppId(),
 | 
					            log.warn("[createOrder][appId({}) merchantOrderId({}) 已经存在对应的支付单({})]", order.getAppId(),
 | 
				
			||||||
                    order.getMerchantOrderId(), toJsonString(order)); // 理论来说,不会出现这个情况
 | 
					                    order.getMerchantOrderId(), toJsonString(order)); // 理论来说,不会出现这个情况
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -26,12 +26,12 @@ import cn.iocoder.yudao.module.pay.service.app.PayAppService;
 | 
				
			|||||||
import cn.iocoder.yudao.module.pay.service.channel.PayChannelService;
 | 
					import cn.iocoder.yudao.module.pay.service.channel.PayChannelService;
 | 
				
			||||||
import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService;
 | 
					import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService;
 | 
				
			||||||
import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
 | 
					import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
 | 
				
			||||||
 | 
					import jakarta.annotation.Resource;
 | 
				
			||||||
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;
 | 
				
			||||||
import org.springframework.validation.annotation.Validated;
 | 
					import org.springframework.validation.annotation.Validated;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import jakarta.annotation.Resource;
 | 
					 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 | 
					import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 | 
				
			||||||
@@ -93,9 +93,9 @@ public class PayRefundServiceImpl implements PayRefundService {
 | 
				
			|||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public Long createPayRefund(PayRefundCreateReqDTO reqDTO) {
 | 
					    public Long createPayRefund(PayRefundCreateReqDTO reqDTO) {
 | 
				
			||||||
        // 1.1 校验 App
 | 
					        // 1.1 校验 App
 | 
				
			||||||
        PayAppDO app = appService.validPayApp(reqDTO.getAppId());
 | 
					        PayAppDO app = appService.validPayApp(reqDTO.getAppKey());
 | 
				
			||||||
        // 1.2 校验支付订单
 | 
					        // 1.2 校验支付订单
 | 
				
			||||||
        PayOrderDO order = validatePayOrderCanRefund(reqDTO);
 | 
					        PayOrderDO order = validatePayOrderCanRefund(reqDTO, app.getId());
 | 
				
			||||||
        // 1.3 校验支付渠道是否有效
 | 
					        // 1.3 校验支付渠道是否有效
 | 
				
			||||||
        PayChannelDO channel = channelService.validPayChannel(order.getChannelId());
 | 
					        PayChannelDO channel = channelService.validPayChannel(order.getChannelId());
 | 
				
			||||||
        PayClient client = channelService.getPayClient(channel.getId());
 | 
					        PayClient client = channelService.getPayClient(channel.getId());
 | 
				
			||||||
@@ -153,8 +153,8 @@ public class PayRefundServiceImpl implements PayRefundService {
 | 
				
			|||||||
     * @param reqDTO 退款申请信息
 | 
					     * @param reqDTO 退款申请信息
 | 
				
			||||||
     * @return 支付订单
 | 
					     * @return 支付订单
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    private PayOrderDO validatePayOrderCanRefund(PayRefundCreateReqDTO reqDTO) {
 | 
					    private PayOrderDO validatePayOrderCanRefund(PayRefundCreateReqDTO reqDTO, Long appId) {
 | 
				
			||||||
        PayOrderDO order = orderService.getOrder(reqDTO.getAppId(), reqDTO.getMerchantOrderId());
 | 
					        PayOrderDO order = orderService.getOrder(appId, reqDTO.getMerchantOrderId());
 | 
				
			||||||
        if (order == null) {
 | 
					        if (order == null) {
 | 
				
			||||||
            throw exception(PAY_ORDER_NOT_FOUND);
 | 
					            throw exception(PAY_ORDER_NOT_FOUND);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -164,11 +164,11 @@ public class PayRefundServiceImpl implements PayRefundService {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // 校验金额,退款金额不能大于原定的金额
 | 
					        // 校验金额,退款金额不能大于原定的金额
 | 
				
			||||||
        if (reqDTO.getPrice() + order.getRefundPrice() > order.getPrice()){
 | 
					        if (reqDTO.getPrice() + order.getRefundPrice() > order.getPrice()) {
 | 
				
			||||||
            throw exception(REFUND_PRICE_EXCEED);
 | 
					            throw exception(REFUND_PRICE_EXCEED);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        // 是否有退款中的订单
 | 
					        // 是否有退款中的订单
 | 
				
			||||||
        if (refundMapper.selectCountByAppIdAndOrderId(reqDTO.getAppId(), order.getId(),
 | 
					        if (refundMapper.selectCountByAppIdAndOrderId(appId, order.getId(),
 | 
				
			||||||
                PayRefundStatusEnum.WAITING.getStatus()) > 0) {
 | 
					                PayRefundStatusEnum.WAITING.getStatus()) > 0) {
 | 
				
			||||||
            throw exception(REFUND_HAS_REFUNDING);
 | 
					            throw exception(REFUND_HAS_REFUNDING);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -197,9 +197,10 @@ public class PayRefundServiceImpl implements PayRefundService {
 | 
				
			|||||||
     * 通知并更新订单的退款结果
 | 
					     * 通知并更新订单的退款结果
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
     * @param channel 支付渠道
 | 
					     * @param channel 支付渠道
 | 
				
			||||||
     * @param notify 通知
 | 
					     * @param notify  通知
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    @Transactional(rollbackFor = Exception.class)  // 注意,如果是方法内调用该方法,需要通过 getSelf().notifyRefund(channel, notify) 调用,否则事务不生效
 | 
					    @Transactional(rollbackFor = Exception.class)
 | 
				
			||||||
 | 
					    // 注意,如果是方法内调用该方法,需要通过 getSelf().notifyRefund(channel, notify) 调用,否则事务不生效
 | 
				
			||||||
    public void notifyRefund(PayChannelDO channel, PayRefundRespDTO notify) {
 | 
					    public void notifyRefund(PayChannelDO channel, PayRefundRespDTO notify) {
 | 
				
			||||||
        // 情况一:退款成功
 | 
					        // 情况一:退款成功
 | 
				
			||||||
        if (PayRefundStatusRespEnum.isSuccess(notify.getStatus())) {
 | 
					        if (PayRefundStatusRespEnum.isSuccess(notify.getStatus())) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,12 +24,12 @@ import cn.iocoder.yudao.module.pay.enums.transfer.PayTransferStatusEnum;
 | 
				
			|||||||
import cn.iocoder.yudao.module.pay.service.app.PayAppService;
 | 
					import cn.iocoder.yudao.module.pay.service.app.PayAppService;
 | 
				
			||||||
import cn.iocoder.yudao.module.pay.service.channel.PayChannelService;
 | 
					import cn.iocoder.yudao.module.pay.service.channel.PayChannelService;
 | 
				
			||||||
import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService;
 | 
					import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService;
 | 
				
			||||||
 | 
					import jakarta.annotation.Resource;
 | 
				
			||||||
 | 
					import jakarta.validation.Validator;
 | 
				
			||||||
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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import jakarta.annotation.Resource;
 | 
					 | 
				
			||||||
import jakarta.validation.Validator;
 | 
					 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 | 
					import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 | 
				
			||||||
@@ -79,16 +79,16 @@ public class PayTransferServiceImpl implements PayTransferService {
 | 
				
			|||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public Long createTransfer(PayTransferCreateReqDTO reqDTO) {
 | 
					    public Long createTransfer(PayTransferCreateReqDTO reqDTO) {
 | 
				
			||||||
        // 1.1 校验 App
 | 
					        // 1.1 校验 App
 | 
				
			||||||
        PayAppDO payApp = appService.validPayApp(reqDTO.getAppId());
 | 
					        PayAppDO payApp = appService.validPayApp(reqDTO.getAppKey());
 | 
				
			||||||
        // 1.2 校验支付渠道是否有效
 | 
					        // 1.2 校验支付渠道是否有效
 | 
				
			||||||
        PayChannelDO channel = channelService.validPayChannel(reqDTO.getAppId(), reqDTO.getChannelCode());
 | 
					        PayChannelDO channel = channelService.validPayChannel(payApp.getId(), reqDTO.getChannelCode());
 | 
				
			||||||
        PayClient client = channelService.getPayClient(channel.getId());
 | 
					        PayClient client = channelService.getPayClient(channel.getId());
 | 
				
			||||||
        if (client == null) {
 | 
					        if (client == null) {
 | 
				
			||||||
            log.error("[createTransfer][渠道编号({}) 找不到对应的支付客户端]", channel.getId());
 | 
					            log.error("[createTransfer][渠道编号({}) 找不到对应的支付客户端]", channel.getId());
 | 
				
			||||||
            throw exception(CHANNEL_NOT_FOUND);
 | 
					            throw exception(CHANNEL_NOT_FOUND);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        // 1.3 校验转账单已经发起过转账。
 | 
					        // 1.3 校验转账单已经发起过转账。
 | 
				
			||||||
        PayTransferDO transfer = validateTransferCanCreate(reqDTO);
 | 
					        PayTransferDO transfer = validateTransferCanCreate(reqDTO, payApp.getId());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (transfer == null) {
 | 
					        if (transfer == null) {
 | 
				
			||||||
            // 2.不存在创建转账单. 否则允许使用相同的 no 再次发起转账
 | 
					            // 2.不存在创建转账单. 否则允许使用相同的 no 再次发起转账
 | 
				
			||||||
@@ -116,8 +116,8 @@ public class PayTransferServiceImpl implements PayTransferService {
 | 
				
			|||||||
        return transfer.getId();
 | 
					        return transfer.getId();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private PayTransferDO validateTransferCanCreate(PayTransferCreateReqDTO dto) {
 | 
					    private PayTransferDO validateTransferCanCreate(PayTransferCreateReqDTO dto, Long appId) {
 | 
				
			||||||
        PayTransferDO transfer = transferMapper.selectByAppIdAndMerchantTransferId(dto.getAppId(), dto.getMerchantTransferId());
 | 
					        PayTransferDO transfer = transferMapper.selectByAppIdAndMerchantTransferId(appId, dto.getMerchantTransferId());
 | 
				
			||||||
        if (transfer != null) {
 | 
					        if (transfer != null) {
 | 
				
			||||||
            // 已经存在,并且状态不为等待状态。说明已经调用渠道转账并返回结果.
 | 
					            // 已经存在,并且状态不为等待状态。说明已经调用渠道转账并返回结果.
 | 
				
			||||||
            if (!PayTransferStatusEnum.isWaiting(transfer.getStatus())) {
 | 
					            if (!PayTransferStatusEnum.isWaiting(transfer.getStatus())) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -54,7 +54,7 @@ public class PayWalletRechargeServiceImpl implements PayWalletRechargeService {
 | 
				
			|||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * TODO 芋艿:放到 payconfig
 | 
					     * TODO 芋艿:放到 payconfig
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    private static final Long WALLET_PAY_APP_ID = 8L;
 | 
					    private static final String WALLET_PAY_APP_KEY = "wallet";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private static final String WALLET_RECHARGE_ORDER_SUBJECT = "钱包余额充值";
 | 
					    private static final String WALLET_RECHARGE_ORDER_SUBJECT = "钱包余额充值";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -92,7 +92,7 @@ public class PayWalletRechargeServiceImpl implements PayWalletRechargeService {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        // 2.1 创建支付单
 | 
					        // 2.1 创建支付单
 | 
				
			||||||
        Long payOrderId = payOrderService.createOrder(new PayOrderCreateReqDTO()
 | 
					        Long payOrderId = payOrderService.createOrder(new PayOrderCreateReqDTO()
 | 
				
			||||||
                .setAppId(WALLET_PAY_APP_ID).setUserIp(userIp)
 | 
					                .setAppKey(WALLET_PAY_APP_KEY).setUserIp(userIp)
 | 
				
			||||||
                .setMerchantOrderId(recharge.getId().toString()) // 业务的订单编号
 | 
					                .setMerchantOrderId(recharge.getId().toString()) // 业务的订单编号
 | 
				
			||||||
                .setSubject(WALLET_RECHARGE_ORDER_SUBJECT).setBody("")
 | 
					                .setSubject(WALLET_RECHARGE_ORDER_SUBJECT).setBody("")
 | 
				
			||||||
                .setPrice(recharge.getPayPrice())
 | 
					                .setPrice(recharge.getPayPrice())
 | 
				
			||||||
@@ -174,7 +174,7 @@ public class PayWalletRechargeServiceImpl implements PayWalletRechargeService {
 | 
				
			|||||||
        String walletRechargeId = String.valueOf(id);
 | 
					        String walletRechargeId = String.valueOf(id);
 | 
				
			||||||
        String refundId = walletRechargeId + "-refund";
 | 
					        String refundId = walletRechargeId + "-refund";
 | 
				
			||||||
        Long payRefundId = payRefundService.createPayRefund(new PayRefundCreateReqDTO()
 | 
					        Long payRefundId = payRefundService.createPayRefund(new PayRefundCreateReqDTO()
 | 
				
			||||||
                .setAppId(WALLET_PAY_APP_ID).setUserIp(userIp)
 | 
					                .setAppKey(WALLET_PAY_APP_KEY).setUserIp(userIp)
 | 
				
			||||||
                .setMerchantOrderId(walletRechargeId)
 | 
					                .setMerchantOrderId(walletRechargeId)
 | 
				
			||||||
                .setMerchantRefundId(refundId)
 | 
					                .setMerchantRefundId(refundId)
 | 
				
			||||||
                .setReason("想退钱").setPrice(walletRecharge.getPayPrice()));
 | 
					                .setReason("想退钱").setPrice(walletRecharge.getPayPrice()));
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -218,11 +218,11 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
 | 
				
			|||||||
    public void testCreateOrder_success() {
 | 
					    public void testCreateOrder_success() {
 | 
				
			||||||
        // mock 参数
 | 
					        // mock 参数
 | 
				
			||||||
        PayOrderCreateReqDTO reqDTO = randomPojo(PayOrderCreateReqDTO.class,
 | 
					        PayOrderCreateReqDTO reqDTO = randomPojo(PayOrderCreateReqDTO.class,
 | 
				
			||||||
                o -> o.setAppId(1L).setMerchantOrderId("10")
 | 
					                o -> o.setAppKey("demo").setMerchantOrderId("10")
 | 
				
			||||||
                        .setSubject(randomString()).setBody(randomString()));
 | 
					                        .setSubject(randomString()).setBody(randomString()));
 | 
				
			||||||
        // mock 方法
 | 
					        // mock 方法
 | 
				
			||||||
        PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L).setOrderNotifyUrl("http://127.0.0.1"));
 | 
					        PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L).setOrderNotifyUrl("http://127.0.0.1"));
 | 
				
			||||||
        when(appService.validPayApp(eq(reqDTO.getAppId()))).thenReturn(app);
 | 
					        when(appService.validPayApp(eq(reqDTO.getAppKey()))).thenReturn(app);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // 调用
 | 
					        // 调用
 | 
				
			||||||
        Long orderId = orderService.createOrder(reqDTO);
 | 
					        Long orderId = orderService.createOrder(reqDTO);
 | 
				
			||||||
@@ -239,7 +239,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
 | 
				
			|||||||
    public void testCreateOrder_exists() {
 | 
					    public void testCreateOrder_exists() {
 | 
				
			||||||
        // mock 参数
 | 
					        // mock 参数
 | 
				
			||||||
        PayOrderCreateReqDTO reqDTO = randomPojo(PayOrderCreateReqDTO.class,
 | 
					        PayOrderCreateReqDTO reqDTO = randomPojo(PayOrderCreateReqDTO.class,
 | 
				
			||||||
                o -> o.setAppId(1L).setMerchantOrderId("10"));
 | 
					                o -> o.setAppKey("demo").setMerchantOrderId("10"));
 | 
				
			||||||
        // mock 数据
 | 
					        // mock 数据
 | 
				
			||||||
        PayOrderDO dbOrder = randomPojo(PayOrderDO.class,  o -> o.setAppId(1L).setMerchantOrderId("10"));
 | 
					        PayOrderDO dbOrder = randomPojo(PayOrderDO.class,  o -> o.setAppId(1L).setMerchantOrderId("10"));
 | 
				
			||||||
        orderMapper.insert(dbOrder);
 | 
					        orderMapper.insert(dbOrder);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -209,7 +209,7 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest {
 | 
				
			|||||||
    @Test
 | 
					    @Test
 | 
				
			||||||
    public void testCreateRefund_orderNotFound() {
 | 
					    public void testCreateRefund_orderNotFound() {
 | 
				
			||||||
        PayRefundCreateReqDTO reqDTO = randomPojo(PayRefundCreateReqDTO.class,
 | 
					        PayRefundCreateReqDTO reqDTO = randomPojo(PayRefundCreateReqDTO.class,
 | 
				
			||||||
                o -> o.setAppId(1L));
 | 
					                o -> o.setAppKey("demo"));
 | 
				
			||||||
        // mock 方法(app)
 | 
					        // mock 方法(app)
 | 
				
			||||||
        PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L));
 | 
					        PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L));
 | 
				
			||||||
        when(appService.validPayApp(eq(1L))).thenReturn(app);
 | 
					        when(appService.validPayApp(eq(1L))).thenReturn(app);
 | 
				
			||||||
@@ -232,7 +232,7 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest {
 | 
				
			|||||||
    private void testCreateRefund_orderWaitingOrClosed(Integer status) {
 | 
					    private void testCreateRefund_orderWaitingOrClosed(Integer status) {
 | 
				
			||||||
        // 准备参数
 | 
					        // 准备参数
 | 
				
			||||||
        PayRefundCreateReqDTO reqDTO = randomPojo(PayRefundCreateReqDTO.class,
 | 
					        PayRefundCreateReqDTO reqDTO = randomPojo(PayRefundCreateReqDTO.class,
 | 
				
			||||||
                o -> o.setAppId(1L).setMerchantOrderId("100"));
 | 
					                o -> o.setAppKey("demo").setMerchantOrderId("100"));
 | 
				
			||||||
        // mock 方法(app)
 | 
					        // mock 方法(app)
 | 
				
			||||||
        PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L));
 | 
					        PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L));
 | 
				
			||||||
        when(appService.validPayApp(eq(1L))).thenReturn(app);
 | 
					        when(appService.validPayApp(eq(1L))).thenReturn(app);
 | 
				
			||||||
@@ -249,7 +249,7 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest {
 | 
				
			|||||||
    public void testCreateRefund_refundPriceExceed() {
 | 
					    public void testCreateRefund_refundPriceExceed() {
 | 
				
			||||||
        // 准备参数
 | 
					        // 准备参数
 | 
				
			||||||
        PayRefundCreateReqDTO reqDTO = randomPojo(PayRefundCreateReqDTO.class,
 | 
					        PayRefundCreateReqDTO reqDTO = randomPojo(PayRefundCreateReqDTO.class,
 | 
				
			||||||
                o -> o.setAppId(1L).setMerchantOrderId("100").setPrice(10));
 | 
					                o -> o.setAppKey("demo").setMerchantOrderId("100").setPrice(10));
 | 
				
			||||||
        // mock 方法(app)
 | 
					        // mock 方法(app)
 | 
				
			||||||
        PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L));
 | 
					        PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L));
 | 
				
			||||||
        when(appService.validPayApp(eq(1L))).thenReturn(app);
 | 
					        when(appService.validPayApp(eq(1L))).thenReturn(app);
 | 
				
			||||||
@@ -268,7 +268,7 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest {
 | 
				
			|||||||
    public void testCreateRefund_orderHasRefunding() {
 | 
					    public void testCreateRefund_orderHasRefunding() {
 | 
				
			||||||
        // 准备参数
 | 
					        // 准备参数
 | 
				
			||||||
        PayRefundCreateReqDTO reqDTO = randomPojo(PayRefundCreateReqDTO.class,
 | 
					        PayRefundCreateReqDTO reqDTO = randomPojo(PayRefundCreateReqDTO.class,
 | 
				
			||||||
                o -> o.setAppId(1L).setMerchantOrderId("100").setPrice(10));
 | 
					                o -> o.setAppKey("demo").setMerchantOrderId("100").setPrice(10));
 | 
				
			||||||
        // mock 方法(app)
 | 
					        // mock 方法(app)
 | 
				
			||||||
        PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L));
 | 
					        PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L));
 | 
				
			||||||
        when(appService.validPayApp(eq(1L))).thenReturn(app);
 | 
					        when(appService.validPayApp(eq(1L))).thenReturn(app);
 | 
				
			||||||
@@ -291,7 +291,7 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest {
 | 
				
			|||||||
    public void testCreateRefund_channelNotFound() {
 | 
					    public void testCreateRefund_channelNotFound() {
 | 
				
			||||||
        // 准备参数
 | 
					        // 准备参数
 | 
				
			||||||
        PayRefundCreateReqDTO reqDTO = randomPojo(PayRefundCreateReqDTO.class,
 | 
					        PayRefundCreateReqDTO reqDTO = randomPojo(PayRefundCreateReqDTO.class,
 | 
				
			||||||
                o -> o.setAppId(1L).setMerchantOrderId("100").setPrice(9));
 | 
					                o -> o.setAppKey("demo").setMerchantOrderId("100").setPrice(9));
 | 
				
			||||||
        // mock 方法(app)
 | 
					        // mock 方法(app)
 | 
				
			||||||
        PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L));
 | 
					        PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L));
 | 
				
			||||||
        when(appService.validPayApp(eq(1L))).thenReturn(app);
 | 
					        when(appService.validPayApp(eq(1L))).thenReturn(app);
 | 
				
			||||||
@@ -315,7 +315,7 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest {
 | 
				
			|||||||
    public void testCreateRefund_refundExists() {
 | 
					    public void testCreateRefund_refundExists() {
 | 
				
			||||||
        // 准备参数
 | 
					        // 准备参数
 | 
				
			||||||
        PayRefundCreateReqDTO reqDTO = randomPojo(PayRefundCreateReqDTO.class,
 | 
					        PayRefundCreateReqDTO reqDTO = randomPojo(PayRefundCreateReqDTO.class,
 | 
				
			||||||
                o -> o.setAppId(1L).setMerchantOrderId("100").setPrice(9)
 | 
					                o -> o.setAppKey("demo").setMerchantOrderId("100").setPrice(9)
 | 
				
			||||||
                        .setMerchantRefundId("200").setReason("测试退款"));
 | 
					                        .setMerchantRefundId("200").setReason("测试退款"));
 | 
				
			||||||
        // mock 方法(app)
 | 
					        // mock 方法(app)
 | 
				
			||||||
        PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L));
 | 
					        PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L));
 | 
				
			||||||
@@ -347,7 +347,7 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest {
 | 
				
			|||||||
    public void testCreateRefund_invokeException() {
 | 
					    public void testCreateRefund_invokeException() {
 | 
				
			||||||
        // 准备参数
 | 
					        // 准备参数
 | 
				
			||||||
        PayRefundCreateReqDTO reqDTO = randomPojo(PayRefundCreateReqDTO.class,
 | 
					        PayRefundCreateReqDTO reqDTO = randomPojo(PayRefundCreateReqDTO.class,
 | 
				
			||||||
                o -> o.setAppId(1L).setMerchantOrderId("100").setPrice(9)
 | 
					                o -> o.setAppKey("demo").setMerchantOrderId("100").setPrice(9)
 | 
				
			||||||
                        .setMerchantRefundId("200").setReason("测试退款"));
 | 
					                        .setMerchantRefundId("200").setReason("测试退款"));
 | 
				
			||||||
        // mock 方法(app)
 | 
					        // mock 方法(app)
 | 
				
			||||||
        PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L));
 | 
					        PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L));
 | 
				
			||||||
@@ -391,7 +391,7 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            // 准备参数
 | 
					            // 准备参数
 | 
				
			||||||
            PayRefundCreateReqDTO reqDTO = randomPojo(PayRefundCreateReqDTO.class,
 | 
					            PayRefundCreateReqDTO reqDTO = randomPojo(PayRefundCreateReqDTO.class,
 | 
				
			||||||
                    o -> o.setAppId(1L).setMerchantOrderId("100").setPrice(9)
 | 
					                    o -> o.setAppKey("demo").setMerchantOrderId("100").setPrice(9)
 | 
				
			||||||
                            .setMerchantRefundId("200").setReason("测试退款"));
 | 
					                            .setMerchantRefundId("200").setReason("测试退款"));
 | 
				
			||||||
            // mock 方法(app)
 | 
					            // mock 方法(app)
 | 
				
			||||||
            PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L));
 | 
					            PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L));
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -33,80 +33,80 @@
 | 
				
			|||||||
        </dependency>
 | 
					        </dependency>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <!-- 会员中心。默认注释,保证编译速度 -->
 | 
					        <!-- 会员中心。默认注释,保证编译速度 -->
 | 
				
			||||||
<!--        <dependency>-->
 | 
					        <dependency>
 | 
				
			||||||
<!--            <groupId>cn.iocoder.boot</groupId>-->
 | 
					            <groupId>cn.iocoder.boot</groupId>
 | 
				
			||||||
<!--            <artifactId>yudao-module-member-biz</artifactId>-->
 | 
					            <artifactId>yudao-module-member-biz</artifactId>
 | 
				
			||||||
<!--            <version>${revision}</version>-->
 | 
					            <version>${revision}</version>
 | 
				
			||||||
<!--        </dependency>-->
 | 
					        </dependency>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <!-- 数据报表。默认注释,保证编译速度 -->
 | 
					        <!-- 数据报表。默认注释,保证编译速度 -->
 | 
				
			||||||
<!--        <dependency>-->
 | 
					        <dependency>
 | 
				
			||||||
<!--            <groupId>cn.iocoder.boot</groupId>-->
 | 
					            <groupId>cn.iocoder.boot</groupId>
 | 
				
			||||||
<!--            <artifactId>yudao-module-report-biz</artifactId>-->
 | 
					            <artifactId>yudao-module-report-biz</artifactId>
 | 
				
			||||||
<!--            <version>${revision}</version>-->
 | 
					            <version>${revision}</version>
 | 
				
			||||||
<!--        </dependency>-->
 | 
					        </dependency>
 | 
				
			||||||
        <!-- 工作流。默认注释,保证编译速度 -->
 | 
					        <!-- 工作流。默认注释,保证编译速度 -->
 | 
				
			||||||
<!--        <dependency>-->
 | 
					        <dependency>
 | 
				
			||||||
<!--            <groupId>cn.iocoder.boot</groupId>-->
 | 
					            <groupId>cn.iocoder.boot</groupId>
 | 
				
			||||||
<!--            <artifactId>yudao-module-bpm-biz</artifactId>-->
 | 
					            <artifactId>yudao-module-bpm-biz</artifactId>
 | 
				
			||||||
<!--            <version>${revision}</version>-->
 | 
					            <version>${revision}</version>
 | 
				
			||||||
<!--        </dependency>-->
 | 
					        </dependency>
 | 
				
			||||||
        <!-- 支付服务。默认注释,保证编译速度 -->
 | 
					        <!-- 支付服务。默认注释,保证编译速度 -->
 | 
				
			||||||
<!--        <dependency>-->
 | 
					        <dependency>
 | 
				
			||||||
<!--            <groupId>cn.iocoder.boot</groupId>-->
 | 
					            <groupId>cn.iocoder.boot</groupId>
 | 
				
			||||||
<!--            <artifactId>yudao-module-pay-biz</artifactId>-->
 | 
					            <artifactId>yudao-module-pay-biz</artifactId>
 | 
				
			||||||
<!--            <version>${revision}</version>-->
 | 
					            <version>${revision}</version>
 | 
				
			||||||
<!--        </dependency>-->
 | 
					        </dependency>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <!-- 微信公众号模块。默认注释,保证编译速度 -->
 | 
					        <!-- 微信公众号模块。默认注释,保证编译速度 -->
 | 
				
			||||||
<!--        <dependency>-->
 | 
					        <dependency>
 | 
				
			||||||
<!--            <groupId>cn.iocoder.boot</groupId>-->
 | 
					            <groupId>cn.iocoder.boot</groupId>
 | 
				
			||||||
<!--            <artifactId>yudao-module-mp-biz</artifactId>-->
 | 
					            <artifactId>yudao-module-mp-biz</artifactId>
 | 
				
			||||||
<!--            <version>${revision}</version>-->
 | 
					            <version>${revision}</version>
 | 
				
			||||||
<!--        </dependency>-->
 | 
					        </dependency>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <!-- 商城相关模块。默认注释,保证编译速度-->
 | 
					        <!-- 商城相关模块。默认注释,保证编译速度-->
 | 
				
			||||||
<!--        <dependency>-->
 | 
					        <dependency>
 | 
				
			||||||
<!--            <groupId>cn.iocoder.boot</groupId>-->
 | 
					            <groupId>cn.iocoder.boot</groupId>
 | 
				
			||||||
<!--            <artifactId>yudao-module-promotion-biz</artifactId>-->
 | 
					            <artifactId>yudao-module-promotion-biz</artifactId>
 | 
				
			||||||
<!--            <version>${revision}</version>-->
 | 
					            <version>${revision}</version>
 | 
				
			||||||
<!--        </dependency>-->
 | 
					        </dependency>
 | 
				
			||||||
<!--        <dependency>-->
 | 
					        <dependency>
 | 
				
			||||||
<!--            <groupId>cn.iocoder.boot</groupId>-->
 | 
					            <groupId>cn.iocoder.boot</groupId>
 | 
				
			||||||
<!--            <artifactId>yudao-module-product-biz</artifactId>-->
 | 
					            <artifactId>yudao-module-product-biz</artifactId>
 | 
				
			||||||
<!--            <version>${revision}</version>-->
 | 
					            <version>${revision}</version>
 | 
				
			||||||
<!--        </dependency>-->
 | 
					        </dependency>
 | 
				
			||||||
<!--        <dependency>-->
 | 
					        <dependency>
 | 
				
			||||||
<!--            <groupId>cn.iocoder.boot</groupId>-->
 | 
					            <groupId>cn.iocoder.boot</groupId>
 | 
				
			||||||
<!--            <artifactId>yudao-module-trade-biz</artifactId>-->
 | 
					            <artifactId>yudao-module-trade-biz</artifactId>
 | 
				
			||||||
<!--            <version>${revision}</version>-->
 | 
					            <version>${revision}</version>
 | 
				
			||||||
<!--        </dependency>-->
 | 
					        </dependency>
 | 
				
			||||||
<!--        <dependency>-->
 | 
					        <dependency>
 | 
				
			||||||
<!--            <groupId>cn.iocoder.boot</groupId>-->
 | 
					            <groupId>cn.iocoder.boot</groupId>
 | 
				
			||||||
<!--            <artifactId>yudao-module-statistics-biz</artifactId>-->
 | 
					            <artifactId>yudao-module-statistics-biz</artifactId>
 | 
				
			||||||
<!--            <version>${revision}</version>-->
 | 
					            <version>${revision}</version>
 | 
				
			||||||
<!--        </dependency>-->
 | 
					        </dependency>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <!-- CRM 相关模块。默认注释,保证编译速度 -->
 | 
					        <!-- CRM 相关模块。默认注释,保证编译速度 -->
 | 
				
			||||||
<!--        <dependency>-->
 | 
					        <dependency>
 | 
				
			||||||
<!--            <groupId>cn.iocoder.boot</groupId>-->
 | 
					            <groupId>cn.iocoder.boot</groupId>
 | 
				
			||||||
<!--            <artifactId>yudao-module-crm-biz</artifactId>-->
 | 
					            <artifactId>yudao-module-crm-biz</artifactId>
 | 
				
			||||||
<!--            <version>${revision}</version>-->
 | 
					            <version>${revision}</version>
 | 
				
			||||||
<!--        </dependency>-->
 | 
					        </dependency>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <!-- ERP 相关模块。默认注释,保证编译速度 -->
 | 
					        <!-- ERP 相关模块。默认注释,保证编译速度 -->
 | 
				
			||||||
<!--        <dependency>-->
 | 
					        <dependency>
 | 
				
			||||||
<!--            <groupId>cn.iocoder.boot</groupId>-->
 | 
					            <groupId>cn.iocoder.boot</groupId>
 | 
				
			||||||
<!--            <artifactId>yudao-module-erp-biz</artifactId>-->
 | 
					            <artifactId>yudao-module-erp-biz</artifactId>
 | 
				
			||||||
<!--            <version>${revision}</version>-->
 | 
					            <version>${revision}</version>
 | 
				
			||||||
<!--        </dependency>-->
 | 
					        </dependency>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <!-- AI 大模型相关模块。默认注释,保证编译速度 -->
 | 
					        <!-- AI 大模型相关模块。默认注释,保证编译速度 -->
 | 
				
			||||||
<!--        <dependency>-->
 | 
					        <dependency>
 | 
				
			||||||
<!--            <groupId>cn.iocoder.boot</groupId>-->
 | 
					            <groupId>cn.iocoder.boot</groupId>
 | 
				
			||||||
<!--            <artifactId>yudao-module-ai-biz</artifactId>-->
 | 
					            <artifactId>yudao-module-ai-biz</artifactId>
 | 
				
			||||||
<!--            <version>${revision}</version>-->
 | 
					            <version>${revision}</version>
 | 
				
			||||||
<!--        </dependency>-->
 | 
					        </dependency>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <!-- spring boot 配置所需依赖 -->
 | 
					        <!-- spring boot 配置所需依赖 -->
 | 
				
			||||||
        <dependency>
 | 
					        <dependency>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -45,7 +45,7 @@ spring:
 | 
				
			|||||||
      primary: master
 | 
					      primary: master
 | 
				
			||||||
      datasource:
 | 
					      datasource:
 | 
				
			||||||
        master:
 | 
					        master:
 | 
				
			||||||
          url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例
 | 
					          url: jdbc:mysql://39.105.15.179:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例
 | 
				
			||||||
          #          url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=true&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai # MySQL Connector/J 5.X 连接的示例
 | 
					          #          url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=true&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai # MySQL Connector/J 5.X 连接的示例
 | 
				
			||||||
          #          url: jdbc:postgresql://127.0.0.1:5432/ruoyi-vue-pro # PostgreSQL 连接的示例
 | 
					          #          url: jdbc:postgresql://127.0.0.1:5432/ruoyi-vue-pro # PostgreSQL 连接的示例
 | 
				
			||||||
          #          url: jdbc:oracle:thin:@127.0.0.1:1521:xe # Oracle 连接的示例
 | 
					          #          url: jdbc:oracle:thin:@127.0.0.1:1521:xe # Oracle 连接的示例
 | 
				
			||||||
@@ -54,26 +54,26 @@ spring:
 | 
				
			|||||||
          #          url: jdbc:kingbase8://127.0.0.1:54321/test  # 人大金仓 KingbaseES 连接的示例
 | 
					          #          url: jdbc:kingbase8://127.0.0.1:54321/test  # 人大金仓 KingbaseES 连接的示例
 | 
				
			||||||
          #          url: jdbc:postgresql://127.0.0.1:5432/postgres # OpenGauss 连接的示例
 | 
					          #          url: jdbc:postgresql://127.0.0.1:5432/postgres # OpenGauss 连接的示例
 | 
				
			||||||
          username: root
 | 
					          username: root
 | 
				
			||||||
          password: 123456
 | 
					          password: 3WLiVUBEwTbvAfsh
 | 
				
			||||||
          #          username: sa # SQL Server 连接的示例
 | 
					          #          username: sa # SQL Server 连接的示例
 | 
				
			||||||
          #          password: Yudao@2024 # SQL Server 连接的示例
 | 
					          #          password: Yudao@2024 # SQL Server 连接的示例
 | 
				
			||||||
          #          username: SYSDBA # DM 连接的示例
 | 
					          #          username: SYSDBA # DM 连接的示例
 | 
				
			||||||
          #          password: SYSDBA001 # DM 连接的示例
 | 
					          #          password: SYSDBA001 # DM 连接的示例
 | 
				
			||||||
          #          username: root # OpenGauss 连接的示例
 | 
					          #          username: root # OpenGauss 连接的示例
 | 
				
			||||||
          #          password: Yudao@2024 # OpenGauss 连接的示例
 | 
					          #          password: Yudao@2024 # OpenGauss 连接的示例
 | 
				
			||||||
        slave: # 模拟从库,可根据自己需要修改
 | 
					#        slave: # 模拟从库,可根据自己需要修改
 | 
				
			||||||
          lazy: true # 开启懒加载,保证启动速度
 | 
					#          lazy: true # 开启懒加载,保证启动速度
 | 
				
			||||||
          url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
 | 
					#          url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
 | 
				
			||||||
          username: root
 | 
					#          username: root
 | 
				
			||||||
          password: 123456
 | 
					#          password: 123456
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优
 | 
					  # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优
 | 
				
			||||||
  data:
 | 
					  data:
 | 
				
			||||||
    redis:
 | 
					    redis:
 | 
				
			||||||
      host: 127.0.0.1 # 地址
 | 
					      host: 39.105.15.179 # 地址
 | 
				
			||||||
      port: 6379 # 端口
 | 
					      port: 6379 # 端口
 | 
				
			||||||
      database: 0 # 数据库索引
 | 
					      database: 0 # 数据库索引
 | 
				
			||||||
#    password: dev # 密码,建议生产环境开启
 | 
					      password: 3WLiVUBEwTbvAfsh # 密码,建议生产环境开启
 | 
				
			||||||
 | 
					
 | 
				
			||||||
--- #################### 定时任务相关配置 ####################
 | 
					--- #################### 定时任务相关配置 ####################
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -110,18 +110,18 @@ spring:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
# rocketmq 配置项,对应 RocketMQProperties 配置类
 | 
					# rocketmq 配置项,对应 RocketMQProperties 配置类
 | 
				
			||||||
rocketmq:
 | 
					rocketmq:
 | 
				
			||||||
  name-server: 127.0.0.1:9876 # RocketMQ Namesrv
 | 
					  name-server: 117.72.39.77:9876 # RocketMQ Namesrv
 | 
				
			||||||
 | 
					
 | 
				
			||||||
spring:
 | 
					#spring:
 | 
				
			||||||
  # RabbitMQ 配置项,对应 RabbitProperties 配置类
 | 
					#  # RabbitMQ 配置项,对应 RabbitProperties 配置类
 | 
				
			||||||
  rabbitmq:
 | 
					#  rabbitmq:
 | 
				
			||||||
    host: 127.0.0.1 # RabbitMQ 服务的地址
 | 
					#    host: 127.0.0.1 # RabbitMQ 服务的地址
 | 
				
			||||||
    port: 5672 # RabbitMQ 服务的端口
 | 
					#    port: 5672 # RabbitMQ 服务的端口
 | 
				
			||||||
    username: rabbit # RabbitMQ 服务的账号
 | 
					#    username: rabbit # RabbitMQ 服务的账号
 | 
				
			||||||
    password: rabbit # RabbitMQ 服务的密码
 | 
					#    password: rabbit # RabbitMQ 服务的密码
 | 
				
			||||||
  # Kafka 配置项,对应 KafkaProperties 配置类
 | 
					#  # Kafka 配置项,对应 KafkaProperties 配置类
 | 
				
			||||||
  kafka:
 | 
					#  kafka:
 | 
				
			||||||
    bootstrap-servers: 127.0.0.1:9092 # 指定 Kafka Broker 地址,可以设置多个,以逗号分隔
 | 
					#    bootstrap-servers: 127.0.0.1:9092 # 指定 Kafka Broker 地址,可以设置多个,以逗号分隔
 | 
				
			||||||
 | 
					
 | 
				
			||||||
--- #################### 服务保障相关配置 ####################
 | 
					--- #################### 服务保障相关配置 ####################
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -309,7 +309,7 @@ yudao:
 | 
				
			|||||||
    end-code: 9999 # 这里配置 9999 的原因是,测试方便。
 | 
					    end-code: 9999 # 这里配置 9999 的原因是,测试方便。
 | 
				
			||||||
  trade:
 | 
					  trade:
 | 
				
			||||||
    order:
 | 
					    order:
 | 
				
			||||||
      app-id: 1 # 商户编号
 | 
					      app-key: mall
 | 
				
			||||||
      pay-expire-time: 2h # 支付的过期时间
 | 
					      pay-expire-time: 2h # 支付的过期时间
 | 
				
			||||||
      receive-expire-time: 14d # 收货的过期时间
 | 
					      receive-expire-time: 14d # 收货的过期时间
 | 
				
			||||||
      comment-expire-time: 7d # 评论的过期时间
 | 
					      comment-expire-time: 7d # 评论的过期时间
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user