本页是 Payment 域抽象层的合同参考。每个方法列出完整签名、参数表、返回类型、异常行为、取消语义与适用场景。所有类型定义于 Bitzsoft.Integrations.Payment 命名空间,源自 src/Bitzsoft.Integrations.Payment/。
接口总览
public interface IPaymentProvider
Task<PaymentResult<PaymentOrderResult>> CreateOrderAsync(
PaymentOrderRequest request, CancellationToken ct = default);
Task<PaymentResult<PaymentStatusResult>> QueryStatusAsync(
string outTradeNo, CancellationToken ct = default);
Task<PaymentResult> CloseOrderAsync(
string outTradeNo, CancellationToken ct = default);
Task<PaymentResult<RefundResult>> RefundAsync(
RefundRequest request, CancellationToken ct = default);
Task<PaymentResult<CallbackVerificationResult>> VerifyCallbackAsync(
CallbackPayload payload, CancellationToken ct = default);
Code 属性
返回 PaymentProviderCode 常量字符串,标识当前供应商。用于多厂商路由、日志关联与审计记录。所有厂商实现返回对应常量值(见下文枚举节)。
CreateOrderAsync
Task<PaymentResult<PaymentOrderResult>> CreateOrderAsync(
PaymentOrderRequest request, CancellationToken ct = default)
创建支付订单。根据 request.Scene 路由到供应商对应接口。
参数
| 参数 | 类型 | 说明 |
|---|
request | PaymentOrderRequest | 支付下单请求,包含订单号、金额、场景等 |
ct | CancellationToken | 取消令牌,默认 default |
返回
PaymentResult<PaymentOrderResult>。成功时 Data 含 PrepayId / PayUrl / QrCode 之一,取决于场景。
异常行为
| 情况 | 行为 |
|---|
request 为 null | 抛 ArgumentNullException(CompatibilityArgument.ThrowIfNull) |
request.OutTradeNo 为空 | 抛 ArgumentNullException(CompatibilityArgument.ThrowIfNullOrEmpty) |
| 不支持的 Scene | 返回 Fail("UNSUPPORTED_SCENE", ...) |
| 供应商业务错误 | 返回 Fail(供应商错误码, 消息) |
| HTTP 非 2xx | 捕获 PaymentException,返回 Fail(ex.ErrorCode, ex.ProviderMessage) |
| 网络异常 | 捕获 HttpRequestException,返回 Fail("HTTP_ERROR", ex.Message) |
ct 取消 | OperationCanceledException 直接传播,不被捕获 |
取消语义
部分场景(App / Web / H5 的支付宝实现)是同步构建签名串,不涉及网络请求,ct 无实际效果。涉及网络请求的场景(如支付宝 Precreate、微信全部场景、Stripe 全部场景)会透传 ct 到 HttpClient,取消时抛 OperationCanceledException。
适用场景
所有支付流程的入口。调用方根据 result.Data 的字段选择前端调起方式:PrepayId 用于 APP SDK 调起,PayUrl 用于浏览器跳转,QrCode 用于生成二维码。
QueryStatusAsync
Task<PaymentResult<PaymentStatusResult>> QueryStatusAsync(
string outTradeNo, CancellationToken ct = default)
按商户订单号查询支付状态。
参数
| 参数 | 类型 | 说明 |
|---|
outTradeNo | string | 商户订单号(调用 CreateOrderAsync 时传入的 OutTradeNo) |
ct | CancellationToken | 取消令牌 |
返回
PaymentResult<PaymentStatusResult>。成功时 Data 含 Status、PaidAmount、PaidAt。
异常行为
| 情况 | 行为 |
|---|
outTradeNo 为 null 或空 | 抛 ArgumentNullException |
| 供应商业务错误 | 返回 Fail(...) |
| 订单不存在 | 返回 Fail("NOT_FOUND", ...)(Stripe 实现) |
| HTTP 非 2xx / 网络异常 | 同 CreateOrderAsync |
取消语义
ct 透传到 HttpClient.GetAsync / PostAsync,取消时抛 OperationCanceledException。
适用场景
- 支付页面轮询订单状态(用户支付后前端跳转前确认)
- 回调未到达时的补偿查询
- 退款前确认订单已支付
CloseOrderAsync
Task<PaymentResult> CloseOrderAsync(
string outTradeNo, CancellationToken ct = default)
关闭未支付订单,阻止后续支付。
参数
| 参数 | 类型 | 说明 |
|---|
outTradeNo | string | 商户订单号 |
ct | CancellationToken | 取消令牌 |
返回
非泛型 PaymentResult。仅表示成功 / 失败,无 Data。
异常行为
| 情况 | 行为 |
|---|
outTradeNo 为 null 或空 | 抛 ArgumentNullException |
| 订单已支付 | 返回 Fail(...)(供应商拒绝关闭已支付订单) |
| HTTP 非 2xx / 网络异常 | 同上 |
适用场景
订单超时未支付时主动关闭,释放库存。Stripe 实现会先将订单过期(expire Session),若传入的不是 Session ID 会先查询再关闭。
RefundAsync
Task<PaymentResult<RefundResult>> RefundAsync(
RefundRequest request, CancellationToken ct = default)
申请退款。支持全额与部分退款。
参数
| 参数 | 类型 | 说明 |
|---|
request | RefundRequest | 退款请求 |
ct | CancellationToken | 取消令牌 |
返回
PaymentResult<RefundResult>。成功时 Data 含退款状态与金额。
异常行为
| 情况 | 行为 |
|---|
request 为 null | 抛 ArgumentNullException |
request.OutTradeNo 或 RefundNo 为空 | 抛 ArgumentNullException |
| 退款金额超过可退金额 | 返回 Fail(...) |
| HTTP 非 2xx / 网络异常 | 同上 |
适用场景
用户申请退款、订单异常退款。部分退款通过 RefundAmount < 原订单金额 实现。Stripe 实现中,若 OutTradeNo 不是 pi_ 前缀的 PaymentIntent ID,会先通过 Checkout Session 解析。
VerifyCallbackAsync
Task<PaymentResult<CallbackVerificationResult>> VerifyCallbackAsync(
CallbackPayload payload, CancellationToken ct = default)
验证支付回调签名并解析回调内容。
参数
| 参数 | 类型 | 说明 |
|---|
payload | CallbackPayload | 回调请求载荷,含 Body / Headers / QueryString |
ct | CancellationToken | 取消令牌(多数实现为同步验签,不实际使用) |
返回
PaymentResult<CallbackVerificationResult>。验签失败返回 Fail("SIGN_VERIFY_FAILED", ...),成功时 Data 含订单号、金额、状态。
异常行为
| 情况 | 行为 |
|---|
payload 为 null | 抛 ArgumentNullException |
| 签名不匹配 | 返回 Fail("SIGN_VERIFY_FAILED", "回调签名验证失败") |
| 缺少签名头(微信 / Stripe) | 返回 Fail("MISSING_HEADERS", ...) 或 Fail("MISSING_SIGNATURE", ...) |
| 回调体非合法 JSON | 返回 Fail("INVALID_BODY", ...) |
| 回调解密失败(微信) | 返回 Fail("DECRYPT_FAILED", ...) |
取消语义
返回 Task.FromResult(支付宝 / Stripe)或同步完成(微信验签后解密),ct 实际不影响。微信支付的 HTTP 已在回调接收前完成。
适用场景
所有支付回调的统一入口。控制器接收原始 HTTP 请求后构造 CallbackPayload,调用此方法验签。验签通过后根据 Status 更新业务订单状态。
PaymentResult<T>
public sealed class PaymentResult<T>
public bool IsSuccess { get; init; }
public T? Data { get; init; }
public string? ErrorCode { get; init; }
public string? ErrorMessage { get; init; }
public static PaymentResult<T> Success(T data);
public static PaymentResult<T> Fail(string errorCode, string errorMessage);
属性
| 属性 | 类型 | 说明 |
|---|
IsSuccess | bool | 操作是否成功。init-only |
Data | T? | 结果数据,成功时有值 |
ErrorCode | string? | 供应商原始错误码 |
ErrorMessage | string? | 错误消息 |
工厂方法
| 方法 | 签名 | 说明 |
|---|
Success | Success(T data) | 创建成功结果,IsSuccess = true,Data = data |
Fail | Fail(string errorCode, string errorMessage) | 创建失败结果,IsSuccess = false,填充错误信息 |
PaymentResult(非泛型)
public sealed class PaymentResult
public bool IsSuccess { get; init; }
public string? ErrorCode { get; init; }
public string? ErrorMessage { get; init; }
public static PaymentResult Success();
public static PaymentResult Fail(string errorCode, string errorMessage);
用于 CloseOrderAsync 等无数据操作。Success() 无参,仅设置 IsSuccess = true。
PaymentException
public class PaymentException : IntegrationException
public string ProviderName { get; } // 供应商名称
public string? ErrorCode { get; } // 供应商原始错误码
public string? ProviderMessage { get; } // 供应商原始错误消息
public PaymentException(string providerName, string? errorCode, string? providerMessage);
public PaymentException(string providerName, string? errorCode, string? providerMessage, Exception innerException);
属性
| 属性 | 类型 | 说明 |
|---|
ProviderName | string | 供应商标识(如 "alipay"),来自基类 Provider |
ErrorCode | string? | 供应商原始错误码(new 关键字重新暴露基类成员) |
ProviderMessage | string? | 供应商原始错误消息 |
Message 格式
[{providerName}] {errorCode}: {providerMessage}
示例:[alipay] HTTP_400: 支付宝网关请求失败: HTTP 400
构造函数
| 构造函数 | 说明 |
|---|
(providerName, errorCode, providerMessage) | 基础构造,domain 固定为 "Payment" |
(providerName, errorCode, providerMessage, innerException) | 带内部异常 |
抛出时机
仅在 HTTP 层非 2xx 时由 HttpClient 封装抛出。Provider 方法捕获后转为 Fail,不会传播到调用方。
DTO 字段表
PaymentOrderRequest
| 字段 | 类型 | 默认值 | 说明 |
|---|
OutTradeNo | string | "" | 商户订单号,需在商户体系内唯一 |
Subject | string | "" | 订单标题 / 商品描述 |
TotalAmount | long | 0 | 订单总金额,单位:分 |
Currency | string | "CNY" | 币种代码,ISO 4217 |
Scene | PaymentScene | Web | 支付场景 |
NotifyUrl | string? | null | 异步通知回调地址(覆盖 Options 全局配置) |
ReturnUrl | string? | null | 同步跳转返回地址 |
OpenId | string? | null | 用户 OpenId,JSAPI 场景必填 |
AuthCode | string? | null | 付款码 / 授权码,扫码当面付场景必填 |
Extra | IDictionary<string, string>? | null | 透传给供应商的扩展参数 |
PaymentOrderResult
| 字段 | 类型 | 说明 |
|---|
OutTradeNo | string | 商户订单号 |
PayUrl | string? | 支付跳转 URL(Web / H5 场景) |
QrCode | string? | 二维码链接(Code 场景,前端据此生成二维码) |
PrepayId | string? | 预支付交易会话标识(App 场景) |
RawResponse | string? | 供应商原始响应 JSON |
场景与结果字段对应关系:
| Scene | 使用字段 |
|---|
| App | PrepayId(支付宝为完整签名串) |
| Web / H5 | PayUrl |
| Code | QrCode |
PaymentStatusResult
| 字段 | 类型 | 说明 |
|---|
OutTradeNo | string | 商户订单号 |
TradeNo | string? | 供应商交易流水号 |
Status | PaymentStatus | 支付状态 |
PaidAmount | long | 实付金额,单位:分 |
PaidAt | DateTimeOffset? | 支付完成时间 |
RefundRequest
| 字段 | 类型 | 说明 |
|---|
OutTradeNo | string | 原商户订单号 |
RefundNo | string | 商户退款单号,需唯一 |
RefundAmount | long | 退款金额,单位:分。0 或等于原金额为全额退款 |
TotalAmount | long | 原订单总金额,微信退款接口要求 |
Reason | string? | 退款原因 |
OutRequestId | string? | 商户请求幂等号,部分供应商用于退款幂等控制 |
RefundResult
| 字段 | 类型 | 说明 |
|---|
RefundNo | string | 商户退款单号 |
Status | RefundStatus | 退款状态 |
RefundAmount | long | 退款金额,单位:分 |
RefundedAt | DateTimeOffset? | 退款完成时间 |
CallbackPayload
| 字段 | 类型 | 默认值 | 说明 |
|---|
Body | string | "" | 回调请求体,原始字符串 |
Headers | IDictionary<string, string> | 空 Dictionary | 回调请求头集合,大小写不敏感。用于验签所需的签名头、时间戳头 |
QueryString | string? | null | 回调 URL 查询字符串,部分供应商签名位于 query 参数中 |
CallbackVerificationResult
| 字段 | 类型 | 说明 |
|---|
OutTradeNo | string | 商户订单号 |
TradeNo | string? | 供应商交易流水号 |
PaidAmount | long | 实付金额,单位:分 |
PaidAt | DateTimeOffset? | 支付完成时间 |
Status | PaymentStatus | 支付状态 |
RawData | string? | 供应商原始响应数据 |
枚举
PaymentScene
| 值 | 名称 | 数值 | 说明 |
|---|
App | APP 支付 | 0 | 原生 APP SDK 调起 |
Web | 电脑网站支付 | 1 | PC 网页跳转 |
H5 | 手机网站支付 | 2 | 移动端浏览器跳转 |
Code | 扫码支付 / 当面付 | 3 | 生成二维码或付款码扣款 |
PaymentStatus
| 值 | 名称 | 数值 | 说明 |
|---|
Pending | 待支付 | 0 | 订单已创建,等待买家付款 |
Success | 支付成功 | 1 | 买家已完成付款 |
Closed | 已关闭 | 2 | 订单已关闭,不可支付 |
Refunded | 已退款 | 3 | 订单已退款 |
Failed | 支付失败 | 4 | 支付过程出错 |
RefundStatus
| 值 | 名称 | 数值 | 说明 |
|---|
Pending | 退款处理中 | 0 | 退款申请已受理,处理中 |
Success | 退款成功 | 1 | 退款已到账 |
Failed | 退款失败 | 2 | 退款被拒绝或失败 |
Abnormal | 退款异常 | 3 | 退款状态异常,需人工介入 |
PaymentProviderCode
静态常量类,非枚举:
| 常量 | 值 |
|---|
Alipay | "alipay" |
WeChatPay | "wechatpay" |
Stripe | "stripe" |
IPaymentConfigProvider<TOptions>
public interface IPaymentConfigProvider<TOptions> where TOptions : class
TOptions Current { get; }
string HttpClientName { get; }
| 属性 | 类型 | 说明 |
|---|
Current | TOptions | 当前供应商配置选项 |
HttpClientName | string | HttpClient 注册名称,用于 IHttpClientFactory 创建命名客户端 |
泛型约束 where TOptions : class。默认实现从 IOptions<TOptions> 读取。各厂商有对应的 IXxxConfigProvider 接口(如 IAlipayConfigProvider),均为本接口的具型变体。
相关