Files
soul/lib/payment/types.ts

290 lines
6.3 KiB
TypeScript
Raw Normal View History

/**
* (Universal Payment Module Types)
* Universal_Payment_Module v4.0
*
* 作者: 卡若
* 版本: v4.0
*/
// 支付平台枚举
export type PaymentPlatform = 'alipay' | 'wechat' | 'paypal' | 'stripe' | 'usdt' | 'coin';
// 支付网关类型
export type PaymentGateway =
| 'alipay_web' | 'alipay_wap' | 'alipay_qr'
| 'wechat_native' | 'wechat_jsapi' | 'wechat_h5' | 'wechat_app'
| 'paypal' | 'stripe' | 'usdt' | 'coin';
// 订单状态
export type OrderStatus = 'created' | 'paying' | 'paid' | 'closed' | 'refunded';
// 交易状态
export type TradeStatus = 'paying' | 'paid' | 'closed' | 'refunded';
// 交易类型
export type TradeType = 'purchase' | 'recharge';
// 支付结果类型
export type PaymentResultType = 'url' | 'qrcode' | 'json' | 'address' | 'direct';
// 货币类型
export type Currency = 'CNY' | 'USD' | 'EUR' | 'USDT';
/**
*
*/
export interface CreateOrderParams {
userId: string;
title: string;
amount: number; // 金额(元)
currency?: Currency;
productId?: string;
productType?: 'section' | 'fullbook' | 'membership' | 'vip';
extraParams?: Record<string, unknown>;
}
/**
*
*/
export interface Order {
sn: string; // 订单号
userId: string;
title: string;
priceAmount: number; // 原价(分)
payAmount: number; // 应付金额(分)
currency: Currency;
status: OrderStatus;
productId?: string;
productType?: string;
extraData?: Record<string, unknown>;
paidAt?: Date;
closedAt?: Date;
expiredAt?: Date;
createdAt: Date;
updatedAt: Date;
}
/**
*
*/
export interface CheckoutParams {
orderSn: string;
gateway: PaymentGateway;
returnUrl?: string;
openid?: string; // 微信JSAPI需要
coinAmount?: number; // 虚拟币抵扣
}
/**
*
*/
export interface CreateTradeData {
goodsTitle: string;
goodsDetail?: string;
tradeSn: string;
orderSn: string;
amount: number; // 金额(分)
notifyUrl: string;
returnUrl?: string;
platformType?: string; // web/wap/jsapi/native/h5/app
createIp?: string;
openId?: string;
attach?: Record<string, unknown>;
}
/**
*
*/
export interface TradeResult {
type: PaymentResultType;
payload: string | Record<string, string>;
tradeSn: string;
expiration?: number; // 过期时间(秒)
amount?: number;
coinDeducted?: number;
prepayId?: string; // 微信预支付ID
}
/**
*
*/
export interface NotifyResult {
status: 'paying' | 'paid' | 'closed' | 'refunded' | 'failed';
tradeSn: string;
platformSn: string;
payAmount: number; // 分
payTime: Date;
currency: Currency;
attach?: Record<string, unknown>;
rawData?: Record<string, unknown>;
}
/**
*
*/
export interface PayTrade {
id?: string;
tradeSn: string;
orderSn: string;
userId: string;
title: string;
amount: number; // 分
cashAmount: number; // 现金支付金额(分)
coinAmount: number; // 虚拟币抵扣金额
currency: Currency;
platform: PaymentPlatform;
platformType?: string;
platformSn?: string;
platformCreatedParams?: Record<string, unknown>;
platformCreatedResult?: Record<string, unknown>;
status: TradeStatus;
type: TradeType;
payTime?: Date;
notifyData?: Record<string, unknown>;
sellerId?: string;
createdAt: Date;
updatedAt: Date;
}
/**
* 退
*/
export interface Refund {
id?: string;
refundSn: string;
tradeSn: string;
orderSn: string;
amount: number; // 分
reason?: string;
status: 'pending' | 'processing' | 'success' | 'failed';
platformRefundSn?: string;
refundedAt?: Date;
operatorId?: string;
createdAt: Date;
updatedAt: Date;
}
/**
*
*/
export interface GatewayConfig {
enabled: boolean;
mode: 'sandbox' | 'production';
[key: string]: unknown;
}
/**
*
*/
export interface AlipayConfig extends GatewayConfig {
appId: string;
pid: string;
sellerEmail?: string;
privateKey?: string;
publicKey?: string;
md5Key?: string;
}
/**
*
*/
export interface WechatConfig extends GatewayConfig {
appId: string;
appSecret?: string;
serviceAppId?: string; // 服务号AppID
serviceSecret?: string;
mchId: string;
mchKey: string;
certPath?: string;
keyPath?: string;
}
/**
*
*/
export interface PaymentResponse<T = unknown> {
code: number;
message: string;
data: T | null;
}
/**
*
*/
export interface PaymentMethod {
gateway: PaymentGateway;
name: string;
icon: string;
enabled: boolean;
available: boolean; // 当前环境是否可用
}
/**
*
*/
export class PaymentException extends Error {
constructor(message: string, public code?: string) {
super(message);
this.name = 'PaymentException';
}
}
export class SignatureError extends PaymentException {
constructor(message = '签名验证失败') {
super(message, 'SIGNATURE_ERROR');
this.name = 'SignatureError';
}
}
export class AmountMismatchError extends PaymentException {
constructor(message = '金额不匹配') {
super(message, 'AMOUNT_MISMATCH');
this.name = 'AmountMismatchError';
}
}
export class GatewayNotFoundError extends PaymentException {
constructor(gateway: string) {
super(`不支持的支付网关: ${gateway}`, 'GATEWAY_NOT_FOUND');
this.name = 'GatewayNotFoundError';
}
}
/**
*
*/
export function yuanToFen(yuan: number): number {
return Math.round(yuan * 100);
}
/**
*
*/
export function fenToYuan(fen: number): number {
return Math.round(fen) / 100;
}
/**
*
* 格式: YYYYMMDD + 6
*/
export function generateOrderSn(prefix = ''): string {
const date = new Date();
const dateStr = date.toISOString().slice(0, 10).replace(/-/g, '');
const random = Math.floor(Math.random() * 1000000).toString().padStart(6, '0');
return `${prefix}${dateStr}${random}`;
}
/**
*
* 格式: T + YYYYMMDDHHMMSS + 5
*/
export function generateTradeSn(prefix = 'T'): string {
const now = new Date();
const timestamp = now.toISOString()
.replace(/[-:T]/g, '')
.slice(0, 14);
const random = Math.floor(Math.random() * 100000).toString().padStart(5, '0');
return `${prefix}${timestamp}${random}`;
}