Files
jurong_circle_black/services/alipayservice.js
2025-09-10 18:10:40 +08:00

322 lines
9.2 KiB
JavaScript
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.

const { AlipaySdk } = require('alipay-sdk');
const { getDB } = require('../database');
const crypto = require('crypto');
const path = require('path');
const fs = require('fs');
class AlipayService {
constructor() {
this.privateKey = null;
this.alipayPublicKey = null;
this.alipaySdk = null;
this.isInitialized = false;
this.initializeAlipay();
}
/**
* 初始化支付宝服务
*/
initializeAlipay() {
try {
// 读取密钥文件
const privateKeyPath = this.resolveCertPath('../certs/alipay-private-key.pem');
const publicKeyPath = this.resolveCertPath('../certs/alipay-public-key.pem');
console.log('支付宝私钥路径:', privateKeyPath);
console.log('支付宝公钥路径:', publicKeyPath);
// 验证文件有效性
if (!this.isValidFile(privateKeyPath)) {
throw new Error(`支付宝私钥文件无效或不存在: ${privateKeyPath}`);
}
if (!this.isValidFile(publicKeyPath)) {
throw new Error(`支付宝公钥文件无效或不存在: ${publicKeyPath}`);
}
console.log('尝试加载支付宝私钥文件:', privateKeyPath);
this.privateKey = fs.readFileSync(privateKeyPath, 'utf8');
console.log('支付宝私钥加载成功');
console.log('尝试加载支付宝公钥文件:', publicKeyPath);
this.alipayPublicKey = fs.readFileSync(publicKeyPath, 'utf8');
console.log('支付宝公钥加载成功');
this.initializeSDK();
} catch (error) {
console.error('支付宝服务初始化失败:', error.message);
console.error('支付宝功能将不可用');
// 不抛出错误,允许服务继续运行
}
}
/**
* 初始化支付宝SDK
*/
initializeSDK() {
if (!this.privateKey || !this.alipayPublicKey) {
console.warn('支付宝密钥未加载跳过SDK初始化');
return;
}
// 支付宝配置
this.config = {
appId: process.env.ALIPAY_APP_ID || '2021001161683774', // 替换为实际的应用ID
privateKey: this.privateKey, // 从文件读取的应用私钥
alipayPublicKey: this.alipayPublicKey, // 从文件读取的支付宝公钥
gateway: 'https://openapi.alipay.com/gateway.do', // 支付宝网关地址
signType: 'RSA2',
charset: 'utf-8',
version: '1.0',
timeout: 5000
};
// 初始化支付宝SDK
this.alipaySdk = new AlipaySdk({
appId: this.config.appId,
privateKey: this.config.privateKey,
alipayPublicKey: this.config.alipayPublicKey,
gateway: this.config.gateway,
signType: this.config.signType,
timeout: this.config.timeout
});
this.isInitialized = true;
console.log('支付宝SDK初始化成功');
}
/**
* 解析证书文件路径
* @param {string} relativePath - 相对路径
* @returns {string} 绝对路径
*/
resolveCertPath(relativePath) {
return path.resolve(__dirname, relativePath);
}
/**
* 验证文件是否有效
* @param {string} filePath - 文件路径
* @returns {boolean} 是否为有效文件
*/
isValidFile(filePath) {
try {
const stats = fs.statSync(filePath);
return stats.isFile();
} catch (error) {
return false;
}
}
/**
* 检查支付宝服务是否已初始化
* @returns {boolean} 是否已初始化
*/
isServiceAvailable() {
return this.isInitialized && this.alipaySdk !== null;
}
/**
* 创建注册支付订单
* @param {Object} params - 支付参数
* @param {string} params.userId - 用户ID
* @param {string} params.username - 用户名
* @param {string} params.phone - 手机号
* @param {string} params.clientIp - 客户端IP
* @returns {Promise<Object>} 支付结果
*/
async createRegistrationPayOrder({ userId, username, phone, clientIp }) {
// 检查服务是否可用
if (!this.isServiceAvailable()) {
throw new Error('支付宝服务未初始化或不可用');
}
try {
const db = getDB();
// 生成订单号
const outTradeNo = this.generateOrderNo();
const totalFee = 39900; // 399元单位
const subject = '用户注册激活费用';
const body = `用户${username}(${phone})注册激活费用`;
// 业务参数
const bizContent = {
out_trade_no: outTradeNo,
total_amount: (totalFee / 100).toFixed(2), // 转换为元
subject: subject,
body: body,
product_code: 'QUICK_WAP_WAY',
quit_url: process.env.ALIPAY_QUIT_URL || 'https://your-domain.com/payment/cancel'
};
// 使用新版SDK的pageExecute方法生成支付URL
const payUrl = this.alipaySdk.pageExecute('alipay.trade.wap.pay', 'GET', {
bizContent: bizContent,
notifyUrl: process.env.ALIPAY_NOTIFY_URL || 'https://your-domain.com/api/payment/alipay/notify',
returnUrl: process.env.ALIPAY_RETURN_URL || 'https://your-domain.com/payment/success'
});
// 保存订单到数据库
await db.execute(
`INSERT INTO payment_orders
(user_id, out_trade_no, total_fee, body, trade_type, status, created_at)
VALUES (?, ?, ?, ?, ?, ?, NOW())`,
[userId, outTradeNo, totalFee, body, 'ALIPAY_WAP', 'pending']
);
console.log('支付宝支付订单创建成功:', {
userId,
outTradeNo,
totalFee,
payUrl
});
return {
success: true,
data: {
outTradeNo,
payUrl,
paymentType: 'alipay_wap',
totalFee
}
};
} catch (error) {
console.error('创建支付宝支付订单失败:', error);
return {
success: false,
message: error.message || '创建支付订单失败'
};
}
}
/**
* 查询支付状态
* @param {string} outTradeNo - 商户订单号
* @returns {Promise<Object>} 查询结果
*/
async queryPaymentStatus(outTradeNo) {
// 检查服务是否可用
if (!this.isServiceAvailable()) {
throw new Error('支付宝服务未初始化或不可用');
}
try {
const result = await this.alipaySdk.exec('alipay.trade.query', {
bizContent: {
out_trade_no: outTradeNo
}
});
if (result.code === '10000') {
// 查询成功
const tradeStatus = result.tradeStatus;
// 如果支付成功,更新数据库
if (tradeStatus === 'TRADE_SUCCESS') {
await this.updatePaymentStatus(outTradeNo, {
status: 'paid',
transactionId: result.tradeNo,
paidAt: new Date()
});
}
return {
success: true,
data: {
trade_status: tradeStatus,
trade_no: result.tradeNo,
total_amount: result.totalAmount,
buyer_pay_amount: result.buyerPayAmount,
gmt_payment: result.gmtPayment
}
};
} else {
return {
success: false,
message: result.msg || '查询支付状态失败'
};
}
} catch (error) {
console.error('查询支付宝支付状态失败:', error);
return {
success: false,
message: error.message || '查询支付状态失败'
};
}
}
/**
* 更新支付状态
* @param {string} outTradeNo - 商户订单号
* @param {Object} updateData - 更新数据
*/
async updatePaymentStatus(outTradeNo, updateData) {
try {
const db = getDB();
// 更新订单状态
await db.execute(
`UPDATE payment_orders
SET status = ?, transaction_id = ?, paid_at = ?
WHERE out_trade_no = ?`,
[updateData.status, updateData.transactionId, updateData.paidAt, outTradeNo]
);
// 如果支付成功,更新用户支付状态
if (updateData.status === 'paid') {
const [orders] = await db.execute(
'SELECT user_id FROM payment_orders WHERE out_trade_no = ?',
[outTradeNo]
);
if (orders.length > 0) {
const userId = orders[0].user_id;
await db.execute(
'UPDATE users SET payment_status = ? WHERE id = ?',
['paid', userId]
);
console.log('用户支付状态更新成功:', { userId, outTradeNo });
}
}
} catch (error) {
console.error('更新支付状态失败:', error);
throw error;
}
}
/**
* 验证支付宝回调签名
* @param {Object} params - 回调参数
* @returns {boolean} 验证结果
*/
verifyNotifySign(params) {
// 检查服务是否可用
if (!this.isServiceAvailable()) {
console.error('支付宝服务未初始化,无法验证签名');
return false;
}
try {
return this.alipaySdk.checkNotifySign(params);
} catch (error) {
console.error('验证支付宝回调签名失败:', error);
return false;
}
}
/**
* 生成订单号
* @returns {string} 订单号
*/
generateOrderNo() {
const timestamp = Date.now();
const random = Math.floor(Math.random() * 1000).toString().padStart(3, '0');
return `ALI${timestamp}${random}`;
}
}
module.exports = AlipayService;