mirror of
				https://gitee.com/hhyykk/ipms-sjy.git
				synced 2025-10-31 02:08:43 +08:00 
			
		
		
		
	Merge branch 'master-jdk17' into feature/db
# Conflicts: # sql/tools/README.md
This commit is contained in:
		| @@ -67,8 +67,8 @@ exit | ||||
|  | ||||
| ① 下载人大金仓 Docker 镜像: | ||||
|  | ||||
| > x86_64版本: https://kingbase.oss-cn-beijing.aliyuncs.com/KESV8R3/V009R001C001B0025-安装包-docker/x86_64/kdb_x86_64_V009R001C001B0025.tar  | ||||
| > aarch64版本:https://kingbase.oss-cn-beijing.aliyuncs.com/KESV8R3/V009R001C001B0025-安装包-docker/aarch64/kdb_aarch64_V009R001C001B0025.tar | ||||
| > x86_64 版本: https://kingbase.oss-cn-beijing.aliyuncs.com/KESV8R3/V009R001C001B0025-安装包-docker/x86_64/kdb_x86_64_V009R001C001B0025.tar  | ||||
| > aarch64 版本:https://kingbase.oss-cn-beijing.aliyuncs.com/KESV8R3/V009R001C001B0025-安装包-docker/aarch64/kdb_aarch64_V009R001C001B0025.tar | ||||
|  | ||||
| ② 加载镜像文件,在镜像 tar 文件所在目录运行: | ||||
|  | ||||
| @@ -80,11 +80,11 @@ docker load -i x86_64/kdb_x86_64_V009R001C001B0025.tar | ||||
|  | ||||
| ```Bash | ||||
| docker compose up -d kingbase | ||||
| # 注意:启动完 dm 后,需要手动再执行如下命令,因为 dm 不支持初始化脚本 | ||||
| docker compose exec kingbase bash -c 'ksql -U $DB_USER -d test -f /tmp/schema.sql' | ||||
| # 注意:启动完 kingbase 后,需要手动再执行如下命令,因为 dm 不支持初始化脚本 | ||||
| docker compose exec kingbase bash -c "exec ksql -Uroot -d test -f /tmp/schema.sql" | ||||
| ``` | ||||
|  | ||||
| **注意**: MyBatis, MyBatis Plus 目前不兼容人大金仓,推荐直接使用PostgreSQL JDBC 驱动,已经 url 配置方式连接数据库。 | ||||
| **注意**: MyBatis、MyBatis Plus 目前不兼容人大金仓,推荐直接使用 PostgreSQL JDBC 驱动,已经 url 配置方式连接数据库。 | ||||
|  | ||||
| ### 1.7 华为 OpenGauss | ||||
|  | ||||
|   | ||||
| @@ -247,15 +247,15 @@ id,name,type,parentId | ||||
| 246,英属印度洋领地,1,0 | ||||
| 247,东萨摩亚,1,0 | ||||
| 248,诺福克岛,1,0 | ||||
| 110000,北京,2,1 | ||||
| 120000,天津,2,1 | ||||
| 110000,北京市,2,1 | ||||
| 120000,天津市,2,1 | ||||
| 130000,河北省,2,1 | ||||
| 140000,山西省,2,1 | ||||
| 150000,内蒙古自治区,2,1 | ||||
| 210000,辽宁省,2,1 | ||||
| 220000,吉林省,2,1 | ||||
| 230000,黑龙江省,2,1 | ||||
| 310000,上海,2,1 | ||||
| 310000,上海市,2,1 | ||||
| 320000,江苏省,2,1 | ||||
| 330000,浙江省,2,1 | ||||
| 340000,安徽省,2,1 | ||||
| @@ -268,7 +268,7 @@ id,name,type,parentId | ||||
| 440000,广东省,2,1 | ||||
| 450000,广西壮族自治区,2,1 | ||||
| 460000,海南省,2,1 | ||||
| 500000,重庆,2,1 | ||||
| 500000,重庆市,2,1 | ||||
| 510000,四川省,2,1 | ||||
| 520000,贵州省,2,1 | ||||
| 530000,云南省,2,1 | ||||
|   | ||||
| 
 | 
| @@ -34,20 +34,24 @@ public class CronUtils { | ||||
|      * @return 满足条件的执行时间 | ||||
|      */ | ||||
|     public static List<LocalDateTime> getNextTimes(String cronExpression, int n) { | ||||
|         // 获得 CronExpression 对象 | ||||
|         // 1. 获得 CronExpression 对象 | ||||
|         CronExpression cron; | ||||
|         try { | ||||
|             cron = new CronExpression(cronExpression); | ||||
|         } catch (ParseException e) { | ||||
|             throw new IllegalArgumentException(e.getMessage()); | ||||
|         } | ||||
|         // 从当前开始计算,n 个满足条件的 | ||||
|         // 2. 从当前开始计算,n 个满足条件的 | ||||
|         Date now = new Date(); | ||||
|         List<LocalDateTime> nextTimes = new ArrayList<>(n); | ||||
|         for (int i = 0; i < n; i++) { | ||||
|             Date nextTime = cron.getNextValidTimeAfter(now); | ||||
|             // 2.1 如果 nextTime 为 null,说明没有更多的有效时间,退出循环 | ||||
|             if (nextTime == null) { | ||||
|                 break; | ||||
|             } | ||||
|             nextTimes.add(LocalDateTimeUtil.of(nextTime)); | ||||
|             // 切换现在,为下一个触发时间; | ||||
|             // 2.2 切换现在,为下一个触发时间; | ||||
|             now = nextTime; | ||||
|         } | ||||
|         return nextTimes; | ||||
|   | ||||
| @@ -12,7 +12,7 @@ | ||||
|     <packaging>jar</packaging> | ||||
|  | ||||
|     <name>${project.artifactId}</name> | ||||
|     <description>服务保证,提供分布式锁、幂等、限流、熔断等等功能</description> | ||||
|     <description>服务保证,提供分布式锁、幂等、限流、熔断、API 签名等等功能</description> | ||||
|     <url>https://github.com/YunaiV/ruoyi-vue-pro</url> | ||||
|  | ||||
|     <dependencies> | ||||
| @@ -35,6 +35,13 @@ | ||||
|             <artifactId>lock4j-redisson-spring-boot-starter</artifactId> | ||||
|             <optional>true</optional> | ||||
|         </dependency> | ||||
|  | ||||
|         <!-- Test 测试相关 --> | ||||
|         <dependency> | ||||
|             <groupId>cn.iocoder.boot</groupId> | ||||
|             <artifactId>yudao-spring-boot-starter-test</artifactId> | ||||
|             <scope>test</scope> | ||||
|         </dependency> | ||||
|     </dependencies> | ||||
|  | ||||
| </project> | ||||
|   | ||||
| @@ -0,0 +1,28 @@ | ||||
| package cn.iocoder.yudao.framework.signature.config; | ||||
|  | ||||
| import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration; | ||||
| import cn.iocoder.yudao.framework.signature.core.aop.ApiSignatureAspect; | ||||
| import cn.iocoder.yudao.framework.signature.core.redis.ApiSignatureRedisDAO; | ||||
| import org.springframework.boot.autoconfigure.AutoConfiguration; | ||||
| import org.springframework.context.annotation.Bean; | ||||
| import org.springframework.data.redis.core.StringRedisTemplate; | ||||
|  | ||||
| /** | ||||
|  * HTTP API 签名的自动配置类 | ||||
|  * | ||||
|  * @author Zhougang | ||||
|  */ | ||||
| @AutoConfiguration(after = YudaoRedisAutoConfiguration.class) | ||||
| public class YudaoApiSignatureAutoConfiguration { | ||||
|  | ||||
|     @Bean | ||||
|     public ApiSignatureAspect signatureAspect(ApiSignatureRedisDAO signatureRedisDAO) { | ||||
|         return new ApiSignatureAspect(signatureRedisDAO); | ||||
|     } | ||||
|  | ||||
|     @Bean | ||||
|     public ApiSignatureRedisDAO signatureRedisDAO(StringRedisTemplate stringRedisTemplate) { | ||||
|         return new ApiSignatureRedisDAO(stringRedisTemplate); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,59 @@ | ||||
| package cn.iocoder.yudao.framework.signature.core.annotation; | ||||
|  | ||||
| import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; | ||||
|  | ||||
| import java.lang.annotation.*; | ||||
| import java.util.concurrent.TimeUnit; | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * HTTP API 签名注解 | ||||
|  * | ||||
|  * @author Zhougang | ||||
|  */ | ||||
| @Inherited | ||||
| @Documented | ||||
| @Target({ElementType.METHOD, ElementType.TYPE}) | ||||
| @Retention(RetentionPolicy.RUNTIME) | ||||
| public @interface ApiSignature { | ||||
|  | ||||
|     /** | ||||
|      * 同一个请求多长时间内有效 默认 60 秒 | ||||
|      */ | ||||
|     int timeout() default 60; | ||||
|  | ||||
|     /** | ||||
|      * 时间单位,默认为 SECONDS 秒 | ||||
|      */ | ||||
|     TimeUnit timeUnit() default TimeUnit.SECONDS; | ||||
|  | ||||
|     // ========================== 签名参数 ========================== | ||||
|  | ||||
|     /** | ||||
|      * 提示信息,签名失败的提示 | ||||
|      * | ||||
|      * @see GlobalErrorCodeConstants#BAD_REQUEST | ||||
|      */ | ||||
|     String message() default "签名不正确"; // 为空时,使用 BAD_REQUEST 错误提示 | ||||
|  | ||||
|     /** | ||||
|      * 签名字段:appId 应用ID | ||||
|      */ | ||||
|     String appId() default "appId"; | ||||
|  | ||||
|     /** | ||||
|      * 签名字段:timestamp 时间戳 | ||||
|      */ | ||||
|     String timestamp() default "timestamp"; | ||||
|  | ||||
|     /** | ||||
|      * 签名字段:nonce 随机数,10 位以上 | ||||
|      */ | ||||
|     String nonce() default "nonce"; | ||||
|  | ||||
|     /** | ||||
|      * sign 客户端签名 | ||||
|      */ | ||||
|     String sign() default "sign"; | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,169 @@ | ||||
| package cn.iocoder.yudao.framework.signature.core.aop; | ||||
|  | ||||
| import cn.hutool.core.lang.Assert; | ||||
| import cn.hutool.core.map.MapUtil; | ||||
| import cn.hutool.core.util.ObjUtil; | ||||
| import cn.hutool.core.util.StrUtil; | ||||
| import cn.hutool.crypto.digest.DigestUtil; | ||||
| import cn.iocoder.yudao.framework.common.exception.ServiceException; | ||||
| import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; | ||||
| import cn.iocoder.yudao.framework.signature.core.annotation.ApiSignature; | ||||
| import cn.iocoder.yudao.framework.signature.core.redis.ApiSignatureRedisDAO; | ||||
| import jakarta.servlet.http.HttpServletRequest; | ||||
| import lombok.AllArgsConstructor; | ||||
| import lombok.extern.slf4j.Slf4j; | ||||
| import org.aspectj.lang.JoinPoint; | ||||
| import org.aspectj.lang.annotation.Aspect; | ||||
| import org.aspectj.lang.annotation.Before; | ||||
|  | ||||
| import java.util.Map; | ||||
| import java.util.Objects; | ||||
| import java.util.SortedMap; | ||||
| import java.util.TreeMap; | ||||
|  | ||||
| import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST; | ||||
|  | ||||
| /** | ||||
|  * 拦截声明了 {@link ApiSignature} 注解的方法,实现签名 | ||||
|  * | ||||
|  * @author Zhougang | ||||
|  */ | ||||
| @Aspect | ||||
| @Slf4j | ||||
| @AllArgsConstructor | ||||
| public class ApiSignatureAspect { | ||||
|  | ||||
|     private final ApiSignatureRedisDAO signatureRedisDAO; | ||||
|  | ||||
|     @Before("@annotation(signature)") | ||||
|     public void beforePointCut(JoinPoint joinPoint, ApiSignature signature) { | ||||
|         // 1. 验证通过,直接结束 | ||||
|         if (verifySignature(signature, Objects.requireNonNull(ServletUtils.getRequest()))) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         // 2. 验证不通过,抛出异常 | ||||
|         log.error("[beforePointCut][方法{} 参数({}) 签名失败]", joinPoint.getSignature().toString(), | ||||
|                 joinPoint.getArgs()); | ||||
|         throw new ServiceException(BAD_REQUEST.getCode(), | ||||
|                 StrUtil.blankToDefault(signature.message(), BAD_REQUEST.getMsg())); | ||||
|     } | ||||
|  | ||||
|     public boolean verifySignature(ApiSignature signature, HttpServletRequest request) { | ||||
|         // 1.1 校验 Header | ||||
|         if (!verifyHeaders(signature, request)) { | ||||
|             return false; | ||||
|         } | ||||
|         // 1.2 校验 appId 是否能获取到对应的 appSecret | ||||
|         String appId = request.getHeader(signature.appId()); | ||||
|         String appSecret = signatureRedisDAO.getAppSecret(appId); | ||||
|         Assert.notNull(appSecret, "[appId({})] 找不到对应的 appSecret", appId); | ||||
|  | ||||
|         // 2. 校验签名【重要!】 | ||||
|         String clientSignature = request.getHeader(signature.sign()); // 客户端签名 | ||||
|         String serverSignatureString = buildSignatureString(signature, request, appSecret); // 服务端签名字符串 | ||||
|         String serverSignature = DigestUtil.sha256Hex(serverSignatureString); // 服务端签名 | ||||
|         if (ObjUtil.notEqual(clientSignature, serverSignature)) { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         // 3. 将 nonce 记入缓存,防止重复使用(重点二:此处需要将 ttl 设定为允许 timestamp 时间差的值 x 2 ) | ||||
|         String nonce = request.getHeader(signature.nonce()); | ||||
|         signatureRedisDAO.setNonce(nonce, signature.timeout() * 2, signature.timeUnit()); | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 校验请求头加签参数 | ||||
|      * | ||||
|      * 1. appId 是否为空 | ||||
|      * 2. timestamp 是否为空,请求是否已经超时,默认 10 分钟 | ||||
|      * 3. nonce 是否为空,随机数是否 10 位以上,是否在规定时间内已经访问过了 | ||||
|      * 4. sign 是否为空 | ||||
|      * | ||||
|      * @param signature signature | ||||
|      * @param request   request | ||||
|      * @return 是否校验 Header 通过 | ||||
|      */ | ||||
|     private boolean verifyHeaders(ApiSignature signature, HttpServletRequest request) { | ||||
|         // 1. 非空校验 | ||||
|         String appId = request.getHeader(signature.appId()); | ||||
|         if (StrUtil.isBlank(appId)) { | ||||
|             return false; | ||||
|         } | ||||
|         String timestamp = request.getHeader(signature.timestamp()); | ||||
|         if (StrUtil.isBlank(timestamp)) { | ||||
|             return false; | ||||
|         } | ||||
|         String nonce = request.getHeader(signature.nonce()); | ||||
|         if (StrUtil.length(nonce) < 10) { | ||||
|             return false; | ||||
|         } | ||||
|         String sign = request.getHeader(signature.sign()); | ||||
|         if (StrUtil.isBlank(sign)) { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         // 2. 检查 timestamp 是否超出允许的范围 (重点一:此处需要取绝对值) | ||||
|         long expireTime = signature.timeUnit().toMillis(signature.timeout()); | ||||
|         long requestTimestamp = Long.parseLong(timestamp); | ||||
|         long timestampDisparity = Math.abs(System.currentTimeMillis() - requestTimestamp); | ||||
|         if (timestampDisparity > expireTime) { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         // 3. 检查 nonce 是否存在,有且仅能使用一次 | ||||
|         return signatureRedisDAO.getNonce(nonce) == null; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 构建签名字符串 | ||||
|      * | ||||
|      * 格式为 = 请求参数 + 请求体 + 请求头 + 密钥 | ||||
|      * | ||||
|      * @param signature signature | ||||
|      * @param request   request | ||||
|      * @param appSecret appSecret | ||||
|      * @return 签名字符串 | ||||
|      */ | ||||
|     private String buildSignatureString(ApiSignature signature, HttpServletRequest request, String appSecret) { | ||||
|         SortedMap<String, String> parameterMap = getRequestParameterMap(request); // 请求头 | ||||
|         SortedMap<String, String> headerMap = getRequestHeaderMap(signature, request); // 请求参数 | ||||
|         String requestBody = StrUtil.nullToDefault(ServletUtils.getBody(request), ""); // 请求体 | ||||
|         return MapUtil.join(parameterMap, "&", "=") | ||||
|                 + requestBody | ||||
|                 + MapUtil.join(headerMap, "&", "=") | ||||
|                 + appSecret; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取请求头加签参数 Map | ||||
|      * | ||||
|      * @param request 请求 | ||||
|      * @param signature 签名注解 | ||||
|      * @return signature params | ||||
|      */ | ||||
|     private static SortedMap<String, String> getRequestHeaderMap(ApiSignature signature, HttpServletRequest request) { | ||||
|         SortedMap<String, String> sortedMap = new TreeMap<>(); | ||||
|         sortedMap.put(signature.appId(), request.getHeader(signature.appId())); | ||||
|         sortedMap.put(signature.timestamp(), request.getHeader(signature.timestamp())); | ||||
|         sortedMap.put(signature.nonce(), request.getHeader(signature.nonce())); | ||||
|         return sortedMap; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取请求参数 Map | ||||
|      * | ||||
|      * @param request 请求 | ||||
|      * @return queryParams | ||||
|      */ | ||||
|     private static SortedMap<String, String> getRequestParameterMap(HttpServletRequest request) { | ||||
|         SortedMap<String, String> sortedMap = new TreeMap<>(); | ||||
|         for (Map.Entry<String, String[]> entry : request.getParameterMap().entrySet()) { | ||||
|             sortedMap.put(entry.getKey(), entry.getValue()[0]); | ||||
|         } | ||||
|         return sortedMap; | ||||
|     } | ||||
|  | ||||
| } | ||||
|  | ||||
| @@ -0,0 +1,57 @@ | ||||
| package cn.iocoder.yudao.framework.signature.core.redis; | ||||
|  | ||||
| import lombok.AllArgsConstructor; | ||||
| import org.springframework.data.redis.core.StringRedisTemplate; | ||||
|  | ||||
| import java.util.concurrent.TimeUnit; | ||||
|  | ||||
| /** | ||||
|  * HTTP API 签名 Redis DAO | ||||
|  * | ||||
|  * @author Zhougang | ||||
|  */ | ||||
| @AllArgsConstructor | ||||
| public class ApiSignatureRedisDAO { | ||||
|  | ||||
|     private final StringRedisTemplate stringRedisTemplate; | ||||
|  | ||||
|     /** | ||||
|      * 验签随机数 | ||||
|      * | ||||
|      * KEY 格式:signature_nonce:%s // 参数为 随机数 | ||||
|      * VALUE 格式:String | ||||
|      * 过期时间:不固定 | ||||
|      */ | ||||
|     private static final String SIGNATURE_NONCE = "api_signature_nonce:%s"; | ||||
|  | ||||
|     /** | ||||
|      * 签名密钥 | ||||
|      * | ||||
|      * HASH 结构 | ||||
|      * KEY 格式:%s // 参数为 appid | ||||
|      * VALUE 格式:String | ||||
|      * 过期时间:永不过期(预加载到 Redis) | ||||
|      */ | ||||
|     private static final String SIGNATURE_APPID = "api_signature_app"; | ||||
|  | ||||
|     // ========== 验签随机数 ========== | ||||
|  | ||||
|     public String getNonce(String nonce) { | ||||
|         return stringRedisTemplate.opsForValue().get(formatNonceKey(nonce)); | ||||
|     } | ||||
|  | ||||
|     public void setNonce(String nonce, int time, TimeUnit timeUnit) { | ||||
|         stringRedisTemplate.opsForValue().set(formatNonceKey(nonce), "", time, timeUnit); | ||||
|     } | ||||
|  | ||||
|     private static String formatNonceKey(String key) { | ||||
|         return String.format(SIGNATURE_NONCE, key); | ||||
|     } | ||||
|  | ||||
|     // ========== 签名密钥 ========== | ||||
|  | ||||
|     public String getAppSecret(String appId) { | ||||
|         return (String) stringRedisTemplate.opsForHash().get(SIGNATURE_APPID, appId); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,6 @@ | ||||
| /** | ||||
|  * HTTP API 签名,校验安全性 | ||||
|  * | ||||
|  * @see <a href="https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_3>微信支付 —— 安全规范</a> | ||||
|  */ | ||||
| package cn.iocoder.yudao.framework.signature; | ||||
| @@ -1,3 +1,4 @@ | ||||
| cn.iocoder.yudao.framework.idempotent.config.YudaoIdempotentConfiguration | ||||
| cn.iocoder.yudao.framework.lock4j.config.YudaoLock4jConfiguration | ||||
| cn.iocoder.yudao.framework.ratelimiter.config.YudaoRateLimiterConfiguration | ||||
| cn.iocoder.yudao.framework.ratelimiter.config.YudaoRateLimiterConfiguration | ||||
| cn.iocoder.yudao.framework.signature.config.YudaoApiSignatureAutoConfiguration | ||||
| @@ -0,0 +1,75 @@ | ||||
| package cn.iocoder.yudao.framework.signature.core; | ||||
|  | ||||
| import cn.hutool.core.map.MapUtil; | ||||
| import cn.hutool.core.util.IdUtil; | ||||
| import cn.hutool.crypto.digest.DigestUtil; | ||||
| import cn.iocoder.yudao.framework.signature.core.annotation.ApiSignature; | ||||
| import cn.iocoder.yudao.framework.signature.core.aop.ApiSignatureAspect; | ||||
| import cn.iocoder.yudao.framework.signature.core.redis.ApiSignatureRedisDAO; | ||||
| import jakarta.servlet.http.HttpServletRequest; | ||||
| import org.junit.jupiter.api.Test; | ||||
| import org.junit.jupiter.api.extension.ExtendWith; | ||||
| import org.mockito.InjectMocks; | ||||
| import org.mockito.Mock; | ||||
| import org.mockito.junit.jupiter.MockitoExtension; | ||||
|  | ||||
| import java.io.BufferedReader; | ||||
| import java.io.IOException; | ||||
| import java.io.StringReader; | ||||
| import java.util.concurrent.TimeUnit; | ||||
|  | ||||
| import static org.junit.jupiter.api.Assertions.assertTrue; | ||||
| import static org.mockito.ArgumentMatchers.eq; | ||||
| import static org.mockito.Mockito.*; | ||||
|  | ||||
| /** | ||||
|  * {@link ApiSignatureTest} 的单元测试 | ||||
|  */ | ||||
| @ExtendWith(MockitoExtension.class) | ||||
| public class ApiSignatureTest { | ||||
|  | ||||
|     @InjectMocks | ||||
|     private ApiSignatureAspect apiSignatureAspect; | ||||
|  | ||||
|     @Mock | ||||
|     private ApiSignatureRedisDAO signatureRedisDAO; | ||||
|  | ||||
|     @Test | ||||
|     public void testSignatureGet() throws IOException { | ||||
|         // 搞一个签名 | ||||
|         Long timestamp = System.currentTimeMillis(); | ||||
|         String nonce = IdUtil.randomUUID(); | ||||
|         String appId = "xxxxxx"; | ||||
|         String appSecret = "yyyyyy"; | ||||
|         String signString = "k1=v1&v1=k1testappId=xxxxxx&nonce=" + nonce + "×tamp=" + timestamp + "yyyyyy"; | ||||
|         String sign = DigestUtil.sha256Hex(signString); | ||||
|  | ||||
|         // 准备参数 | ||||
|         ApiSignature apiSignature = mock(ApiSignature.class); | ||||
|         when(apiSignature.appId()).thenReturn("appId"); | ||||
|         when(apiSignature.timestamp()).thenReturn("timestamp"); | ||||
|         when(apiSignature.nonce()).thenReturn("nonce"); | ||||
|         when(apiSignature.sign()).thenReturn("sign"); | ||||
|         when(apiSignature.timeout()).thenReturn(60); | ||||
|         when(apiSignature.timeUnit()).thenReturn(TimeUnit.SECONDS); | ||||
|         HttpServletRequest request = mock(HttpServletRequest.class); | ||||
|         when(request.getHeader(eq("appId"))).thenReturn(appId); | ||||
|         when(request.getHeader(eq("timestamp"))).thenReturn(String.valueOf(timestamp)); | ||||
|         when(request.getHeader(eq("nonce"))).thenReturn(nonce); | ||||
|         when(request.getHeader(eq("sign"))).thenReturn(sign); | ||||
|         when(request.getParameterMap()).thenReturn(MapUtil.<String, String[]>builder() | ||||
|                 .put("v1", new String[]{"k1"}).put("k1", new String[]{"v1"}).build()); | ||||
|         when(request.getContentType()).thenReturn("application/json"); | ||||
|         when(request.getReader()).thenReturn(new BufferedReader(new StringReader("test"))); | ||||
|         // mock 方法 | ||||
|         when(signatureRedisDAO.getAppSecret(eq(appId))).thenReturn(appSecret); | ||||
|  | ||||
|         // 调用 | ||||
|         boolean result = apiSignatureAspect.verifySignature(apiSignature, request); | ||||
|         // 断言结果 | ||||
|         assertTrue(result); | ||||
|         // 断言调用 | ||||
|         verify(signatureRedisDAO).setNonce(eq(nonce), eq(120), eq(TimeUnit.SECONDS)); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -1,5 +1,6 @@ | ||||
| package cn.iocoder.yudao.module.crm.dal.dataobject.business; | ||||
|  | ||||
| import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; | ||||
| import com.baomidou.mybatisplus.annotation.KeySequence; | ||||
| import com.baomidou.mybatisplus.annotation.TableId; | ||||
| import com.baomidou.mybatisplus.annotation.TableName; | ||||
| @@ -19,7 +20,7 @@ import lombok.*; | ||||
| @Builder | ||||
| @NoArgsConstructor | ||||
| @AllArgsConstructor | ||||
| public class CrmBusinessStatusDO { | ||||
| public class CrmBusinessStatusDO extends BaseDO { | ||||
|  | ||||
|     /** | ||||
|      * 主键 | ||||
|   | ||||
| @@ -28,8 +28,8 @@ public class FileContentDO extends BaseDO { | ||||
|     /** | ||||
|      * 编号,数据库自增 | ||||
|      */ | ||||
|     @TableId(type = IdType.INPUT) | ||||
|     private String id; | ||||
|     @TableId | ||||
|     private Long id; | ||||
|     /** | ||||
|      * 配置编号 | ||||
|      * | ||||
|   | ||||
| @@ -25,7 +25,6 @@ import java.time.LocalDateTime; | ||||
| @KeySequence(value = "infra_api_error_log_seq") | ||||
| public class ApiErrorLogDO extends BaseDO { | ||||
|  | ||||
|  | ||||
|     /** | ||||
|      * {@link #requestParams} 的最大长度 | ||||
|      */ | ||||
|   | ||||
| @@ -342,7 +342,8 @@ public class CodegenEngine { | ||||
|  | ||||
|         // className 相关 | ||||
|         // 去掉指定前缀,将 TestDictType 转换成 DictType. 因为在 create 等方法后,不需要带上 Test 前缀 | ||||
|         String simpleClassName = removePrefix(table.getClassName(), upperFirst(table.getModuleName())); | ||||
|         String simpleClassName = equalsAnyIgnoreCase(table.getClassName(), table.getModuleName()) ? table.getClassName() | ||||
|                 : removePrefix(table.getClassName(), upperFirst(table.getModuleName())); | ||||
|         bindingMap.put("simpleClassName", simpleClassName); | ||||
|         bindingMap.put("simpleClassName_underlineCase", toUnderlineCase(simpleClassName)); // 将 DictType 转换成 dict_type | ||||
|         bindingMap.put("classNameVar", lowerFirst(simpleClassName)); // 将 DictType 转换成 dictType,用于变量 | ||||
|   | ||||
| @@ -1,33 +1,49 @@ | ||||
| package cn.iocoder.yudao.module.trade.service.order; | ||||
|  | ||||
| import cn.hutool.core.util.IdUtil; | ||||
| import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | ||||
| import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; | ||||
| import cn.iocoder.yudao.module.member.api.address.MemberAddressApi; | ||||
| import cn.iocoder.yudao.module.member.api.user.MemberUserApi; | ||||
| import cn.iocoder.yudao.module.pay.api.order.PayOrderApi; | ||||
| import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderRespDTO; | ||||
| import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum; | ||||
| import cn.iocoder.yudao.module.product.api.comment.ProductCommentApi; | ||||
| import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; | ||||
| import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; | ||||
| import cn.iocoder.yudao.module.promotion.api.coupon.CouponApi; | ||||
| import cn.iocoder.yudao.module.system.api.notify.NotifyMessageSendApi; | ||||
| import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.express.DeliveryExpressCreateReqVO; | ||||
| import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderDeliveryReqVO; | ||||
| import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; | ||||
| import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderItemMapper; | ||||
| import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper; | ||||
| import cn.iocoder.yudao.module.trade.dal.redis.no.TradeNoRedisDAO; | ||||
| import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum; | ||||
| import cn.iocoder.yudao.module.trade.enums.order.TradeOrderRefundStatusEnum; | ||||
| import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum; | ||||
| import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderConfig; | ||||
| import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties; | ||||
| import cn.iocoder.yudao.module.trade.service.cart.CartServiceImpl; | ||||
| import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService; | ||||
| import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressServiceImpl; | ||||
| import cn.iocoder.yudao.module.trade.service.message.TradeMessageServiceImpl; | ||||
| import cn.iocoder.yudao.module.trade.service.order.handler.TradeOrderHandler; | ||||
| import cn.iocoder.yudao.module.trade.service.price.TradePriceServiceImpl; | ||||
| import cn.iocoder.yudao.module.trade.service.price.calculator.TradePriceCalculator; | ||||
| import jakarta.annotation.Resource; | ||||
| import org.junit.jupiter.api.BeforeEach; | ||||
| import org.junit.jupiter.api.Disabled; | ||||
| import org.junit.jupiter.api.Test; | ||||
| import org.springframework.boot.test.mock.mockito.MockBean; | ||||
| import org.springframework.context.annotation.Import; | ||||
|  | ||||
| import jakarta.annotation.Resource; | ||||
| import java.time.Duration; | ||||
|  | ||||
| import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; | ||||
| import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; | ||||
| import static org.junit.jupiter.api.Assertions.*; | ||||
| import static org.mockito.ArgumentMatchers.anyString; | ||||
| import static org.mockito.ArgumentMatchers.eq; | ||||
| import static org.mockito.Mockito.when; | ||||
|  | ||||
| @@ -38,7 +54,9 @@ import static org.mockito.Mockito.when; | ||||
|  * @since 2022-09-07 | ||||
|  */ | ||||
| @Disabled // TODO 芋艿:后续 fix 补充的单测 | ||||
| @Import({TradeOrderUpdateServiceImpl.class, TradeOrderConfig.class}) | ||||
| @Import({TradeOrderUpdateServiceImpl.class, TradeOrderConfig.class, CartServiceImpl.class, TradePriceServiceImpl.class, | ||||
|         DeliveryExpressServiceImpl.class, TradeMessageServiceImpl.class | ||||
| }) | ||||
| public class TradeOrderUpdateServiceTest extends BaseDbUnitTest { | ||||
|  | ||||
|     @Resource | ||||
| @@ -55,7 +73,9 @@ public class TradeOrderUpdateServiceTest extends BaseDbUnitTest { | ||||
|     private ProductSpuApi productSpuApi; | ||||
|     @MockBean | ||||
|     private ProductSkuApi productSkuApi; | ||||
| //    @MockBean | ||||
|     @MockBean | ||||
|     private ProductCommentApi productCommentApi; | ||||
|     //    @MockBean | ||||
| //    private PriceApi priceApi; | ||||
|     @MockBean | ||||
|     private PayOrderApi payOrderApi; | ||||
| @@ -66,11 +86,22 @@ public class TradeOrderUpdateServiceTest extends BaseDbUnitTest { | ||||
|  | ||||
|     @MockBean | ||||
|     private TradeOrderProperties tradeOrderProperties; | ||||
|     @MockBean | ||||
|     private TradeNoRedisDAO tradeNoRedisDAO; | ||||
|     @MockBean | ||||
|     private TradeOrderHandler tradeOrderHandler; | ||||
|     @MockBean | ||||
|     private TradePriceCalculator tradePriceCalculator; | ||||
|     @MockBean | ||||
|     private NotifyMessageSendApi notifyMessageSendApi; | ||||
|     @MockBean | ||||
|     private DeliveryExpressService deliveryExpressService; | ||||
|  | ||||
|     @BeforeEach | ||||
|     public void setUp() { | ||||
|         when(tradeOrderProperties.getAppId()).thenReturn(888L); | ||||
|         when(tradeOrderProperties.getPayExpireTime()).thenReturn(Duration.ofDays(1)); | ||||
|         when(tradeNoRedisDAO.generate(anyString())).thenReturn(IdUtil.randomUUID()); | ||||
|     } | ||||
|  | ||||
| //    @Test | ||||
| @@ -259,11 +290,18 @@ public class TradeOrderUpdateServiceTest extends BaseDbUnitTest { | ||||
|         TradeOrderDO order = randomPojo(TradeOrderDO.class, o -> { | ||||
|             o.setId(1L).setStatus(TradeOrderStatusEnum.UNDELIVERED.getStatus()); | ||||
|             o.setLogisticsId(null).setLogisticsNo(null).setDeliveryTime(null); | ||||
|             o.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()); | ||||
|             o.setDeliveryType(DeliveryTypeEnum.EXPRESS.getType()); | ||||
|         }); | ||||
|         tradeOrderMapper.insert(order); | ||||
|  | ||||
|         DeliveryExpressCreateReqVO expressCreateReqVO = new DeliveryExpressCreateReqVO(); | ||||
|         expressCreateReqVO.setCode("code").setName("Name").setLogo("logo").setSort(0).setStatus(CommonStatusEnum.ENABLE.getStatus()); | ||||
|         Long deliveryExpressId = deliveryExpressService.createDeliveryExpress(expressCreateReqVO); | ||||
|         // 准备参数 | ||||
|         TradeOrderDeliveryReqVO deliveryReqVO = new TradeOrderDeliveryReqVO().setId(1L) | ||||
|                 .setLogisticsId(10L).setLogisticsNo("100"); | ||||
|                 .setLogisticsId(deliveryExpressId).setLogisticsNo("100"); | ||||
|  | ||||
|         // mock 方法(支付单) | ||||
|  | ||||
|         // 调用 | ||||
|   | ||||
| @@ -1,128 +1,155 @@ | ||||
| CREATE TABLE IF NOT EXISTS "trade_order" ( | ||||
|      "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, | ||||
|      "no" varchar NOT NULL, | ||||
|      "type" int NOT NULL, | ||||
|      "terminal" int NOT NULL, | ||||
|      "user_id" bigint NOT NULL, | ||||
|      "user_ip" varchar NOT NULL, | ||||
|      "user_remark" varchar, | ||||
|      "status" int NOT NULL, | ||||
|      "product_count" int NOT NULL, | ||||
|      "cancel_type" int, | ||||
|      "remark" varchar, | ||||
|      "pay_status" bit NOT NULL, | ||||
|      "pay_time" datetime, | ||||
|      "finish_time" datetime, | ||||
|      "cancel_time" datetime, | ||||
|      "original_price" int NOT NULL, | ||||
|      "order_price" int NOT NULL, | ||||
|      "discount_price" int NOT NULL, | ||||
|      "delivery_price" int NOT NULL, | ||||
|      "adjust_price" int NOT NULL, | ||||
|      "pay_price" int NOT NULL, | ||||
|      "pay_order_id" bigint, | ||||
|      "pay_channel_code" varchar, | ||||
|      "delivery_template_id" bigint, | ||||
|      "logistics_id" bigint, | ||||
|      "logistics_no" varchar, | ||||
|      "delivery_time" datetime, | ||||
|      "receive_time" datetime, | ||||
|      "receiver_name" varchar NOT NULL, | ||||
|      "receiver_mobile" varchar NOT NULL, | ||||
|      "receiver_area_id" int NOT NULL, | ||||
|      "receiver_post_code" int, | ||||
|      "receiver_detail_address" varchar NOT NULL, | ||||
|      "after_sale_status" int NOT NULL, | ||||
|      "refund_price" int NOT NULL, | ||||
|      "coupon_id" bigint NOT NULL, | ||||
|      "coupon_price" int NOT NULL, | ||||
|      "point_price" int NOT NULL, | ||||
|      "creator" varchar DEFAULT '', | ||||
|      "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||||
|      "updater" varchar DEFAULT '', | ||||
|      "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, | ||||
|      "deleted" bit NOT NULL DEFAULT FALSE, | ||||
|      PRIMARY KEY ("id") | ||||
| CREATE TABLE IF NOT EXISTS "trade_order" | ||||
| ( | ||||
|     "id"                      bigint   NOT NULL GENERATED BY DEFAULT AS IDENTITY, | ||||
|     "no"                      varchar  NOT NULL, | ||||
|     "type"                    int      NOT NULL, | ||||
|     "terminal"                int      NOT NULL, | ||||
|     "user_id"                 bigint   NOT NULL, | ||||
|     "user_ip"                 varchar  NOT NULL, | ||||
|     "user_remark"             varchar, | ||||
|     "status"                  int      NOT NULL, | ||||
|     "product_count"           int      NOT NULL, | ||||
|     "cancel_type"             int, | ||||
|     "remark"                  varchar, | ||||
|     "comment_status"          boolean, | ||||
|     "brokerage_user_id"       bigint, | ||||
|     "pay_status"              bit      NOT NULL, | ||||
|     "pay_time"                datetime, | ||||
|     "finish_time"             datetime, | ||||
|     "cancel_time"             datetime, | ||||
|     "total_price"             int      NULL, | ||||
|     "order_price"             int      NULL, | ||||
|     "discount_price"          int      NOT NULL, | ||||
|     "delivery_price"          int      NOT NULL, | ||||
|     "adjust_price"            int      NOT NULL, | ||||
|     "pay_price"               int      NOT NULL, | ||||
|     "delivery_type"           int      NOT NULL, | ||||
|     "pay_order_id"            bigint, | ||||
|     "pay_channel_code"        varchar, | ||||
|     "delivery_template_id"    bigint, | ||||
|     "logistics_id"            bigint, | ||||
|     "logistics_no"            varchar, | ||||
|     "delivery_time"           datetime, | ||||
|     "receive_time"            datetime, | ||||
|     "receiver_name"           varchar  NOT NULL, | ||||
|     "receiver_mobile"         varchar  NOT NULL, | ||||
|     "receiver_area_id"        int      NOT NULL, | ||||
|     "receiver_post_code"      int, | ||||
|     "receiver_detail_address" varchar  NOT NULL, | ||||
|     "pick_up_store_id"        long     NULL, | ||||
|     "pick_up_verify_code"     varchar  NULL, | ||||
|     "refund_status"           int      NULL, | ||||
|     "refund_price"            int      NULL, | ||||
|     "after_sale_status"       int      NULL, | ||||
|     "coupon_id"               bigint   NOT NULL, | ||||
|     "coupon_price"            int      NOT NULL, | ||||
|     "use_point"               int      NULL, | ||||
|     "point_price"             int      NOT NULL, | ||||
|     "give_point"              int      NULL, | ||||
|     "refund_point"            int      NULL, | ||||
|     "vip_price"               int      NULL, | ||||
|     "seckill_activity_id"     long     NULL, | ||||
|     "bargain_activity_id"     long     NULL, | ||||
|     "bargain_record_id"       long     NULL, | ||||
|     "combination_activity_id" long     NULL, | ||||
|     "combination_head_id"     long     NULL, | ||||
|     "combination_record_id"   long     NULL, | ||||
|     "creator"                 varchar           DEFAULT '', | ||||
|     "create_time"             datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||||
|     "updater"                 varchar           DEFAULT '', | ||||
|     "update_time"             datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, | ||||
|     "deleted"                 bit      NOT NULL DEFAULT FALSE, | ||||
|     PRIMARY KEY ("id") | ||||
| ) COMMENT '交易订单表'; | ||||
|  | ||||
| CREATE TABLE IF NOT EXISTS "trade_order_item" ( | ||||
|       "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, | ||||
|       "user_id" bigint NOT NULL, | ||||
|       "order_id" bigint NOT NULL, | ||||
|       "spu_id" bigint NOT NULL, | ||||
|       "spu_name" varchar NOT NULL, | ||||
|       "sku_id" bigint NOT NULL, | ||||
|       "properties" varchar, | ||||
|       "pic_url" varchar, | ||||
|       "count" int NOT NULL, | ||||
|       "original_price" int NOT NULL, | ||||
|       "original_unit_price" int NOT NULL, | ||||
|       "discount_price" int NOT NULL, | ||||
|       "pay_price" int NOT NULL, | ||||
|       "order_part_price" int NOT NULL, | ||||
|       "order_divide_price" int NOT NULL, | ||||
|       "after_sale_status" int NOT NULL, | ||||
|       "creator" varchar DEFAULT '', | ||||
|       "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||||
|       "updater" varchar DEFAULT '', | ||||
|       "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, | ||||
|       "deleted" bit NOT NULL DEFAULT FALSE, | ||||
|       PRIMARY KEY ("id") | ||||
| CREATE TABLE IF NOT EXISTS "trade_order_item" | ||||
| ( | ||||
|     "id"                bigint   NOT NULL GENERATED BY DEFAULT AS IDENTITY, | ||||
|     "user_id"           bigint   NOT NULL, | ||||
|     "order_id"          bigint   NOT NULL, | ||||
|     "cart_id"           int      NULL, | ||||
|     "spu_id"            bigint   NOT NULL, | ||||
|     "spu_name"          varchar  NOT NULL, | ||||
|     "sku_id"            bigint   NOT NULL, | ||||
|     "properties"        varchar, | ||||
|     "pic_url"           varchar, | ||||
|     "count"             int      NOT NULL, | ||||
|     "comment_status"    boolean  NULL, | ||||
|     "price"             int      NOT NULL, | ||||
|     "discount_price"    int      NOT NULL, | ||||
|     "delivery_price"    int      NULL, | ||||
|     "adjust_price"      int      NULL, | ||||
|     "pay_price"         int      NOT NULL, | ||||
|     "coupon_price"      int      NULL, | ||||
|     "point_price"       int      NULL, | ||||
|     "use_point"         int      NULL, | ||||
|     "give_point"        int      NULL, | ||||
|     "vip_price"         int      NULL, | ||||
|     "after_sale_id"     long     NULL, | ||||
|     "after_sale_status" int      NOT NULL, | ||||
|     "creator"           varchar           DEFAULT '', | ||||
|     "create_time"       datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||||
|     "updater"           varchar           DEFAULT '', | ||||
|     "update_time"       datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, | ||||
|     "deleted"           bit      NOT NULL DEFAULT FALSE, | ||||
|     PRIMARY KEY ("id") | ||||
| ) COMMENT '交易订单明细表'; | ||||
|  | ||||
| CREATE TABLE IF NOT EXISTS "trade_after_sale" ( | ||||
|     "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, | ||||
|     "no" varchar NOT NULL, | ||||
|     "status" int NOT NULL, | ||||
|     "type" int NOT NULL, | ||||
|     "way" int NOT NULL, | ||||
|     "user_id" bigint NOT NULL, | ||||
|     "apply_reason" varchar NOT NULL, | ||||
| CREATE TABLE IF NOT EXISTS "trade_after_sale" | ||||
| ( | ||||
|     "id"             bigint   NOT NULL GENERATED BY DEFAULT AS IDENTITY, | ||||
|     "no"             varchar  NOT NULL, | ||||
|     "status"         int      NOT NULL, | ||||
|     "type"           int      NOT NULL, | ||||
|     "way"            int      NOT NULL, | ||||
|     "user_id"        bigint   NOT NULL, | ||||
|     "apply_reason"   varchar  NOT NULL, | ||||
|     "apply_description" varchar, | ||||
|     "apply_pic_urls" varchar, | ||||
|     "order_id" bigint NOT NULL, | ||||
|     "order_no" varchar NOT NULL, | ||||
|     "order_item_id" bigint NOT NULL, | ||||
|     "spu_id" bigint NOT NULL, | ||||
|     "spu_name" varchar NOT NULL, | ||||
|     "sku_id" bigint NOT NULL, | ||||
|     "properties" varchar, | ||||
|     "pic_url" varchar, | ||||
|     "count" int NOT NULL, | ||||
|     "audit_time" varchar, | ||||
|     "audit_user_id" bigint, | ||||
|     "audit_reason" varchar, | ||||
|     "refund_price" int NOT NULL, | ||||
|     "pay_refund_id" bigint, | ||||
|     "refund_time" varchar, | ||||
|     "logistics_id" bigint, | ||||
|     "logistics_no" varchar, | ||||
|     "delivery_time" varchar, | ||||
|     "receive_time" varchar, | ||||
|     "order_id"       bigint   NOT NULL, | ||||
|     "order_no"       varchar  NOT NULL, | ||||
|     "order_item_id"  bigint   NOT NULL, | ||||
|     "spu_id"         bigint   NOT NULL, | ||||
|     "spu_name"       varchar  NOT NULL, | ||||
|     "sku_id"         bigint   NOT NULL, | ||||
|     "properties"     varchar, | ||||
|     "pic_url"        varchar, | ||||
|     "count"          int      NOT NULL, | ||||
|     "audit_time"     varchar, | ||||
|     "audit_user_id"  bigint, | ||||
|     "audit_reason"   varchar, | ||||
|     "refund_price"   int      NOT NULL, | ||||
|     "pay_refund_id"  bigint, | ||||
|     "refund_time"    varchar, | ||||
|     "logistics_id"   bigint, | ||||
|     "logistics_no"   varchar, | ||||
|     "delivery_time"  varchar, | ||||
|     "receive_time"   varchar, | ||||
|     "receive_reason" varchar, | ||||
|     "creator" varchar DEFAULT '', | ||||
|     "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||||
|     "updater" varchar DEFAULT '', | ||||
|     "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, | ||||
|     "deleted" bit NOT NULL DEFAULT FALSE, | ||||
|     "creator"        varchar           DEFAULT '', | ||||
|     "create_time"    datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||||
|     "updater"        varchar           DEFAULT '', | ||||
|     "update_time"    datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, | ||||
|     "deleted"        bit      NOT NULL DEFAULT FALSE, | ||||
|     PRIMARY KEY ("id") | ||||
| ) COMMENT '交易售后表'; | ||||
|  | ||||
| CREATE TABLE IF NOT EXISTS "trade_after_sale_log" ( | ||||
|     "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, | ||||
|     "user_id" bigint NOT NULL, | ||||
|     "user_type" int NOT NULL, | ||||
|     "after_sale_id" bigint NOT NULL, | ||||
|     "order_id" bigint NOT NULL, | ||||
|     "order_item_id" bigint NOT NULL, | ||||
| CREATE TABLE IF NOT EXISTS "trade_after_sale_log" | ||||
| ( | ||||
|     "id"            bigint   NOT NULL GENERATED BY DEFAULT AS IDENTITY, | ||||
|     "user_id"       bigint   NOT NULL, | ||||
|     "user_type"     int      NOT NULL, | ||||
|     "after_sale_id" bigint   NOT NULL, | ||||
|     "order_id"      bigint   NOT NULL, | ||||
|     "order_item_id" bigint   NOT NULL, | ||||
|     "before_status" int, | ||||
|     "after_status" int NOT NULL, | ||||
|     "content" varchar NOT NULL, | ||||
|     "creator" varchar DEFAULT '', | ||||
|     "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||||
|     "updater" varchar DEFAULT '', | ||||
|     "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, | ||||
|     "deleted" bit NOT NULL DEFAULT FALSE, | ||||
|     "after_status"  int      NOT NULL, | ||||
|     "content"       varchar  NOT NULL, | ||||
|     "creator"       varchar           DEFAULT '', | ||||
|     "create_time"   datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||||
|     "updater"       varchar           DEFAULT '', | ||||
|     "update_time"   datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, | ||||
|     "deleted"       bit      NOT NULL DEFAULT FALSE, | ||||
|     PRIMARY KEY ("id") | ||||
| ) COMMENT '交易售后日志'; | ||||
|  | ||||
| @@ -161,7 +188,7 @@ CREATE TABLE IF NOT EXISTS "trade_brokerage_record" | ||||
|     "updater"       varchar           DEFAULT '', | ||||
|     "update_time"   datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, | ||||
|     "deleted"       bit      NOT NULL DEFAULT FALSE, | ||||
|     "tenant_id"      bigint   not null default '0', | ||||
|     "tenant_id" bigint not null default '0', | ||||
|     PRIMARY KEY ("id") | ||||
| ) COMMENT '佣金记录'; | ||||
| CREATE TABLE IF NOT EXISTS "trade_brokerage_withdraw" | ||||
| @@ -186,6 +213,22 @@ CREATE TABLE IF NOT EXISTS "trade_brokerage_withdraw" | ||||
|     "updater"             varchar           DEFAULT '', | ||||
|     "update_time"         datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, | ||||
|     "deleted"             bit      NOT NULL DEFAULT FALSE, | ||||
|     "tenant_id"      bigint   not null default '0', | ||||
|     "tenant_id" bigint not null default '0', | ||||
|     PRIMARY KEY ("id") | ||||
| ) COMMENT '佣金提现'; | ||||
|  | ||||
| CREATE TABLE IF NOT EXISTS "trade_delivery_express" | ||||
| ( | ||||
|     "id"          int      NOT NULL GENERATED BY DEFAULT AS IDENTITY, | ||||
|     "code"        varchar  NULL, | ||||
|     "name"        varchar, | ||||
|     "logo"        varchar  NULL, | ||||
|     "sort"        int      NOT NULL, | ||||
|     "status"      int      NOT NULL, | ||||
|     "creator"     varchar           DEFAULT '', | ||||
|     "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||||
|     "updater"     varchar           DEFAULT '', | ||||
|     "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, | ||||
|     "deleted"     bit      NOT NULL DEFAULT FALSE, | ||||
|     PRIMARY KEY ("id") | ||||
| ) COMMENT '佣金提现'; | ||||
| @@ -11,6 +11,7 @@ import lombok.Getter; | ||||
| @Getter | ||||
| @AllArgsConstructor | ||||
| public enum SexEnum { | ||||
|  | ||||
|     /** 男 */ | ||||
|     MALE(1), | ||||
|     /** 女 */ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 dhb52
					dhb52