Files
soul-yongping/next-project/lib/payment/factory.ts
2026-02-09 14:43:35 +08:00

247 lines
6.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 支付网关工厂 (Payment Gateway Factory)
* 统一管理所有支付网关,实现工厂模式
*
* 作者: 卡若
* 版本: v4.0
*/
import {
CreateTradeData,
TradeResult,
NotifyResult,
PaymentPlatform,
PaymentGateway,
GatewayNotFoundError,
PaymentMethod
} from './types';
/**
* 抽象支付网关基类
*/
export abstract class AbstractGateway {
protected config: Record<string, unknown>;
constructor(config: Record<string, unknown> = {}) {
this.config = config;
}
/**
* 创建交易
*/
abstract createTrade(data: CreateTradeData): Promise<TradeResult>;
/**
* 验证签名
*/
abstract verifySign(data: Record<string, string>): boolean;
/**
* 解析回调数据
*/
abstract parseNotify(data: string | Record<string, string>): NotifyResult;
/**
* 关闭交易
*/
abstract closeTrade(tradeSn: string): Promise<boolean>;
/**
* 查询交易
*/
abstract queryTrade(tradeSn: string): Promise<NotifyResult | null>;
/**
* 发起退款
*/
abstract refund(tradeSn: string, refundSn: string, amount: number, reason?: string): Promise<boolean>;
/**
* 回调成功响应
*/
successResponse(): string {
return 'success';
}
/**
* 回调失败响应
*/
failResponse(): string {
return 'fail';
}
}
// 网关类型映射
type GatewayClass = new (config: Record<string, unknown>) => AbstractGateway;
/**
* 支付网关工厂
*/
export class PaymentFactory {
private static gateways: Map<string, GatewayClass> = new Map();
/**
* 注册支付网关
*/
static register(name: string, gatewayClass: GatewayClass): void {
this.gateways.set(name, gatewayClass);
console.log(`[PaymentFactory] 注册支付网关: ${name}`);
}
/**
* 创建支付网关实例
* @param gateway 网关名称,格式如 'wechat_jsapi',会取下划线前的部分
*/
static create(gateway: PaymentGateway | string): AbstractGateway {
const gatewayName = gateway.split('_')[0] as PaymentPlatform;
const GatewayClass = this.gateways.get(gatewayName);
if (!GatewayClass) {
throw new GatewayNotFoundError(gateway);
}
const config = this.getGatewayConfig(gatewayName);
return new GatewayClass(config);
}
/**
* 获取网关配置
*/
private static getGatewayConfig(gateway: PaymentPlatform): Record<string, unknown> {
const configMap: Record<PaymentPlatform, () => Record<string, unknown>> = {
alipay: () => ({
// 支付宝新版接口需要 app_id如果没有配置则使用 pid旧版兼容
appId: process.env.ALIPAY_APP_ID || process.env.ALIPAY_PID || '2088511801157159',
pid: process.env.ALIPAY_PID || '2088511801157159',
sellerEmail: process.env.ALIPAY_SELLER_EMAIL || 'zhengzhiqun@vip.qq.com',
privateKey: process.env.ALIPAY_PRIVATE_KEY || '',
publicKey: process.env.ALIPAY_PUBLIC_KEY || '',
md5Key: process.env.ALIPAY_MD5_KEY || 'lz6ey1h3kl9zqkgtjz3avb5gk37wzbrp',
enabled: process.env.ALIPAY_ENABLED === 'true',
mode: process.env.ALIPAY_MODE || 'production',
}),
wechat: () => ({
// 微信支付需要使用绑定了支付功能的服务号AppID
appId: process.env.WECHAT_APPID || 'wx7c0dbf34ddba300d', // 服务号AppID已绑定商户号
appSecret: process.env.WECHAT_APP_SECRET || 'f865ef18c43dfea6cbe3b1f1aebdb82e',
serviceAppId: process.env.WECHAT_SERVICE_APPID || 'wx7c0dbf34ddba300d',
serviceSecret: process.env.WECHAT_SERVICE_SECRET || 'f865ef18c43dfea6cbe3b1f1aebdb82e',
mchId: process.env.WECHAT_MCH_ID || '1318592501',
mchKey: process.env.WECHAT_MCH_KEY || 'wx3e31b068be59ddc131b068be59ddc2',
certPath: process.env.WECHAT_CERT_PATH || '',
keyPath: process.env.WECHAT_KEY_PATH || '',
enabled: process.env.WECHAT_ENABLED === 'true',
mode: process.env.WECHAT_MODE || 'production',
}),
paypal: () => ({
clientId: process.env.PAYPAL_CLIENT_ID || '',
clientSecret: process.env.PAYPAL_CLIENT_SECRET || '',
mode: process.env.PAYPAL_MODE || 'sandbox',
enabled: process.env.PAYPAL_ENABLED === 'true',
}),
stripe: () => ({
publicKey: process.env.STRIPE_PUBLIC_KEY || '',
secretKey: process.env.STRIPE_SECRET_KEY || '',
webhookSecret: process.env.STRIPE_WEBHOOK_SECRET || '',
mode: process.env.STRIPE_MODE || 'test',
enabled: process.env.STRIPE_ENABLED === 'true',
}),
usdt: () => ({
gatewayType: process.env.USDT_GATEWAY_TYPE || 'nowpayments',
apiKey: process.env.NOWPAYMENTS_API_KEY || '',
ipnSecret: process.env.NOWPAYMENTS_IPN_SECRET || '',
enabled: process.env.USDT_ENABLED === 'true',
}),
coin: () => ({
rate: parseInt(process.env.COIN_RATE || '100', 10),
enabled: process.env.COIN_ENABLED === 'true',
}),
};
return configMap[gateway]?.() || {};
}
/**
* 获取已启用的支付网关列表
*/
static getEnabledGateways(): PaymentMethod[] {
const methods: PaymentMethod[] = [];
// 支付宝
if (process.env.ALIPAY_ENABLED === 'true' || true) { // 默认启用
methods.push({
gateway: 'alipay_wap',
name: '支付宝',
icon: '/icons/alipay.png',
enabled: true,
available: true,
});
}
// 微信支付
if (process.env.WECHAT_ENABLED === 'true' || true) { // 默认启用
methods.push({
gateway: 'wechat_native',
name: '微信支付',
icon: '/icons/wechat.png',
enabled: true,
available: true,
});
}
// PayPal
if (process.env.PAYPAL_ENABLED === 'true') {
methods.push({
gateway: 'paypal',
name: 'PayPal',
icon: '/icons/paypal.png',
enabled: true,
available: true,
});
}
// Stripe
if (process.env.STRIPE_ENABLED === 'true') {
methods.push({
gateway: 'stripe',
name: 'Stripe',
icon: '/icons/stripe.png',
enabled: true,
available: true,
});
}
// USDT
if (process.env.USDT_ENABLED === 'true') {
methods.push({
gateway: 'usdt',
name: 'USDT (TRC20)',
icon: '/icons/usdt.png',
enabled: true,
available: true,
});
}
return methods;
}
/**
* 检查网关是否已注册
*/
static hasGateway(name: string): boolean {
return this.gateways.has(name);
}
/**
* 获取所有已注册的网关名称
*/
static getRegisteredGateways(): string[] {
return Array.from(this.gateways.keys());
}
}
// 导出便捷函数
export function createPaymentGateway(gateway: PaymentGateway | string): AbstractGateway {
return PaymentFactory.create(gateway);
}