chore: initialize qiming workspace repository

This commit is contained in:
Codex
2026-05-29 14:22:48 +08:00
commit bfd67a0f2c
10750 changed files with 1885711 additions and 0 deletions

View File

@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.xspaceagi</groupId>
<artifactId>app-platform-pay</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>app-platform-pay-spec</artifactId>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
<dependency>
<groupId>com.xspaceagi</groupId>
<artifactId>app-platform-pay-sdk</artifactId>
</dependency>
<dependency>
<groupId>com.xspaceagi</groupId>
<artifactId>system-spec</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,10 @@
package com.xspaceagi.pay.spec;
/** 支付网关对外文案常量。 */
public final class PayGatewayMessages {
private PayGatewayMessages() {}
/** 网络不可达、超时、响应不可解析等无法拿到网关业务 JSON 时使用。 */
public static final String CONNECT_FAILED = "支付网关连接失败";
}

View File

@@ -0,0 +1,12 @@
package com.xspaceagi.pay.spec;
import java.time.Duration;
/** 支付调度相关时间常量(建单宽限期、补偿扫描等共用)。 */
public final class PayOrderScheduleConstants {
private PayOrderScheduleConstants() {}
/** 本地 {@code gatewaySyncStatus=PENDING} 且无网关单号超过该时间视为可重试/可补偿关单。 */
public static final Duration STALE_GATEWAY_SYNC_PENDING = Duration.ofMinutes(1);
}

View File

@@ -0,0 +1,19 @@
package com.xspaceagi.pay.spec.dto;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class PageResult<T> {
private List<T> records;
private long total;
/** 当前页,从 1 开始 */
private long page;
private long pageSize;
}

View File

@@ -0,0 +1,17 @@
package com.xspaceagi.pay.spec.dto;
import java.time.LocalDateTime;
import lombok.Data;
@Data
public class PayDeveloperAccountAdminPageRequest {
/** 用户名/昵称模糊关键字;先查用户表再按 userId 过滤开发者账户(与系统用户列表检索规则一致,最多取前 500 条匹配用户) */
private String userNameKeyword;
private Long userId;
private LocalDateTime createdStart;
private LocalDateTime createdEnd;
private Integer page;
private Integer pageSize;
}

View File

@@ -0,0 +1,21 @@
package com.xspaceagi.pay.spec.dto;
import lombok.Data;
@Data
public class PayDeveloperAccountAdminSaveRequest {
private Long id;
private Long userId;
private String email;
private String phone;
private String realName;
private String idCardNo;
private String idCardFrontPhotoUrl;
private String idCardBackPhotoUrl;
private String bankName;
private String branchName;
private String bankCardNo;
}

View File

@@ -0,0 +1,9 @@
package com.xspaceagi.pay.spec.dto;
import lombok.Data;
@Data
public class PayDeveloperAccountAdminUserQueryRequest {
private Long userId;
}

View File

@@ -0,0 +1,9 @@
package com.xspaceagi.pay.spec.dto;
import lombok.Data;
@Data
public class PayDeveloperAccountByIdRequest {
private Long id;
}

View File

@@ -0,0 +1,33 @@
package com.xspaceagi.pay.spec.dto;
import java.util.Date;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class PayDeveloperAccountResponse {
private Long id;
private Long tenantId;
/** 关联 {@code user.id} */
private Long userId;
private String userName;
private String email;
private String phone;
private String realName;
private String idCardNo;
/** 身份证正面照片 URL */
private String idCardFrontPhotoUrl;
/** 身份证反面照片 URL */
private String idCardBackPhotoUrl;
private String bankName;
private String branchName;
private String bankCardNo;
private Date created;
private Date modified;
}

View File

@@ -0,0 +1,19 @@
package com.xspaceagi.pay.spec.dto;
import lombok.Data;
@Data
public class PayDeveloperAccountUserSaveRequest {
private Long id;
private String email;
private String phone;
private String realName;
private String idCardNo;
private String idCardFrontPhotoUrl;
private String idCardBackPhotoUrl;
private String bankName;
private String branchName;
private String bankCardNo;
}

View File

@@ -0,0 +1,28 @@
package com.xspaceagi.pay.spec.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class PayGatewayConnectivityResponse {
/** 是否成功联通 */
private boolean reachable;
/** 不可达时的原因说明 */
private String message;
/** 当前租户配置的支付网关基址 */
private String gatewayBaseUrl;
/** 网关返回的服务器时间戳(毫秒) */
private Long gatewayServerTimeMillis;
/** 本次探测往返耗时(毫秒) */
private Long latencyMillis;
}

View File

@@ -0,0 +1,44 @@
package com.xspaceagi.pay.spec.dto;
import com.xspaceagi.pay.sdk.enums.PayChannel;
import com.xspaceagi.pay.sdk.enums.PayMode;
import com.xspaceagi.pay.sdk.enums.PaymentStatus;
import com.xspaceagi.pay.spec.enums.PayBizNotifyStatus;
import com.xspaceagi.pay.spec.enums.PayOrderGatewaySyncStatus;
import java.math.BigDecimal;
import java.util.Date;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class PayOrderItemResponse {
private Long id;
private Long tenantId;
private String bizOrderNo;
private String bizScene;
/** 订单金额(元) */
private BigDecimal orderAmount;
private String subject;
private PayMode payMode;
private PayChannel payChannel;
/** 平台服务费(元) */
private BigDecimal platformFee;
/** 渠道手续费(元) */
private BigDecimal providerFee;
/** 实收金额(元) */
private BigDecimal netAmount;
private String gatewayPaymentOrderNo;
private PayOrderGatewaySyncStatus gatewaySyncStatus;
private PayBizNotifyStatus bizNotifyStatus;
private String gatewayOrderStatus;
private PaymentStatus paymentStatus;
private Date paidAt;
private Date created;
private Date modified;
}

View File

@@ -0,0 +1,37 @@
package com.xspaceagi.pay.spec.dto;
import com.xspaceagi.pay.sdk.enums.PayChannel;
import com.xspaceagi.pay.sdk.enums.PaymentStatus;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import java.time.LocalDateTime;
import lombok.Data;
@Data
public class PayOrderPageQueryRequest {
/** 创建时间起始(含),可选 */
private LocalDateTime createdStart;
/** 创建时间结束(含),可选 */
private LocalDateTime createdEnd;
/** 支付状态 */
private PaymentStatus paymentStatus;
/** 支付渠道,可选 */
private PayChannel payChannel;
/** 业务订单号,可选 */
private String bizOrderNo;
/** 网关支付单号,可选 */
private String gatewayPaymentOrderNo;
@Min(1)
private Integer page;
@Min(1)
@Max(200)
private Integer pageSize;
}

View File

@@ -0,0 +1,30 @@
package com.xspaceagi.pay.spec.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/** 支付结果通知载荷:随 {@link com.xspaceagi.pay.spec.event.PayOrderSettlementNotifyEvent} 在系统内投递。 */
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class PayResultNotifyPayload {
private Long tenantId;
/** 业务场景标识(平台侧落库字段,与 Open API 建单请求无直接对应) */
private String bizScene;
private String bizOrderNo;
private String gatewayPaymentOrderNo;
/** {@link com.xspaceagi.pay.spec.enums.PaymentOrderStatus} 名,超时时可能为 null */
private String paymentOrderStatus;
private Long orderAmount;
private String paidAt;
}

View File

@@ -0,0 +1,10 @@
package com.xspaceagi.pay.spec.enums;
public enum PayBizNotifyStatus {
/** 轮询中 */
POLLING,
/** 已通知(含支付成功、失败/关闭等终态,已通过进程内事件投递) */
NOTIFIED,
/** 轮询耗尽仍未拿到明确终态(业务宜主动查单) */
TIMEOUT
}

View File

@@ -0,0 +1,7 @@
package com.xspaceagi.pay.spec.enums;
public enum PayOrderGatewaySyncStatus {
PENDING,
SUCCESS,
FAILED
}

View File

@@ -0,0 +1,33 @@
package com.xspaceagi.pay.spec.event;
import com.xspaceagi.pay.spec.dto.PayResultNotifyPayload;
import lombok.Value;
/**
* 支付结果通知事件,由支付模块发布;其他模块通过 {@code @EventListener} 订阅。
*
* <p><b>订阅示例</b></p>
*
* <pre>{@code
* // 按场景过滤:仅处理订阅智能体单
* @EventListener(condition = "#event.payload.bizScene == 'SUBSCRIBE_AGENT'")
* public void onSubscribeAgentSettled(PayOrderSettlementNotifyEvent event) {
* PayResultNotifyPayload p = event.getPayload();
* }
*
* // 或方法内判断多场景
* @EventListener
* public void onSubscribeAgent(PayOrderSettlementNotifyEvent event) {
* if (!"SUBSCRIBE_AGENT".equals(event.getPayload().getBizScene())) {
* return;
* }
* }
* }</pre>
*
* <p>监听逻辑若较重,可在方法上再加 {@code @Async}(需启用异步支持),并保持幂等。</p>
*/
@Value
public class PayOrderSettlementNotifyEvent {
PayResultNotifyPayload payload;
}

View File

@@ -0,0 +1,21 @@
package com.xspaceagi.pay.spec.exception;
import com.xspaceagi.system.spec.enums.ErrorCodeEnum;
import com.xspaceagi.system.spec.exception.BizException;
/**
* 支付网关业务失败:对外 {@code code} 仍为平台 {@link ErrorCodeEnum#SYS_ERROR}{@code displayCode} 为网关 code。
*/
public class PayGatewayBizException extends BizException {
private final String displayCode;
public PayGatewayBizException(String gatewayCode, String gatewayMessage) {
super(ErrorCodeEnum.SYS_ERROR.getCode(), gatewayMessage);
this.displayCode = gatewayCode;
}
public String getDisplayCode() {
return displayCode;
}
}

View File

@@ -0,0 +1,38 @@
package com.xspaceagi.pay.spec.exception;
import com.xspaceagi.pay.spec.PayGatewayMessages;
/**
* 调用 qiming-pay 支付网关失败。若响应体为 {@code ApiResponse} JSON{@link #gatewayCode} 为网关 {@code code}
* {@link #getMessage()} 为网关 {@code message};无 {@code gatewayCode} 且为传输类失败时为 {@link PayGatewayMessages#CONNECT_FAILED}。
*/
public class PayGatewayClientException extends RuntimeException {
private final String gatewayCode;
/** 传输/协议类失败,对外固定文案。 */
public PayGatewayClientException() {
this(null, PayGatewayMessages.CONNECT_FAILED);
}
public PayGatewayClientException(String message) {
this(null, message);
}
public PayGatewayClientException(String gatewayCode, String gatewayMessage) {
super(gatewayMessage != null && !gatewayMessage.isBlank() ? gatewayMessage : PayGatewayMessages.CONNECT_FAILED);
this.gatewayCode = gatewayCode;
}
public String getGatewayCode() {
return gatewayCode;
}
public String getGatewayMessage() {
return getMessage();
}
public boolean hasGatewayApiError() {
return gatewayCode != null && !gatewayCode.isBlank();
}
}

View File

@@ -0,0 +1,4 @@
package com.xspaceagi.pay.spec.gateway;
/** 调用 qiming-pay Open API 时的出站上下文 */
public record PayGatewayOutbound(String baseUrl, String clientId, String clientSecret) {}

View File

@@ -0,0 +1,13 @@
package com.xspaceagi.pay.spec.gateway;
/** 可选注入 {@link PayGatewayOutboundCacheEvictor} 时的空安全调用。 */
public final class PayGatewayOutboundCacheEvictSupport {
private PayGatewayOutboundCacheEvictSupport() {}
public static void evictIfPresent(PayGatewayOutboundCacheEvictor evictor, Long tenantId) {
if (evictor != null && tenantId != null) {
evictor.evict(tenantId);
}
}
}

View File

@@ -0,0 +1,9 @@
package com.xspaceagi.pay.spec.gateway;
/**
* 租户支付网关出站凭证缓存失效(如 {@code paymentGateway}、client 密钥变更后调用)。
*/
public interface PayGatewayOutboundCacheEvictor {
void evict(long tenantId);
}