278 lines
11 KiB
JavaScript
278 lines
11 KiB
JavaScript
|
||
let alipay = require("alipay-sdk");
|
||
const AlipaySdkConfig = {
|
||
appId: process.env.CONFIG_ALIPAY_MINI_APPID,
|
||
privateKey:process.env.CONFIG_ALIPAY_MINI_PRIVATE_KEY,
|
||
alipayPublicKey:process.env.CONFIG_ALIPAY_MINI_PUBLIC_KEY,
|
||
};
|
||
const AlipaySdk = alipay.AlipaySdk;
|
||
const alipaySdk = new AlipaySdk(AlipaySdkConfig);
|
||
const notifyUrl = process.env.CONFIG_ALIPAY_PAY_NOTIFY
|
||
|
||
console.log('===============支付宝AppId')
|
||
console.log(AlipaySdkConfig.appId)
|
||
console.log('===============支付宝公钥')
|
||
console.log(AlipaySdkConfig.alipayPublicKey)
|
||
console.log('===============支付宝私钥')
|
||
console.log(AlipaySdkConfig.privateKey)
|
||
const TradeStatus = {
|
||
WAIT_BUYER_PAY: 'WAIT_BUYER_PAY',//交易创建,等待买家付款
|
||
TRADE_CLOSED: 'TRADE_CLOSED',//未付款交易超时关闭,或支付完成后全额退款
|
||
TRADE_SUCCESS: 'TRADE_SUCCESS',//交易成功
|
||
TRADE_FINISHED: 'TRADE_FINISHED',//交易完成
|
||
}
|
||
|
||
class aliplayApi {
|
||
/**
|
||
* 获取accToken
|
||
* @param {obj} param0
|
||
*/
|
||
static async accToken({ code }) {
|
||
try {
|
||
let params = {
|
||
grantType: 'authorization_code',
|
||
code,
|
||
};
|
||
let options = {};
|
||
let res = await alipaySdk.exec("alipay.system.oauth.token", params, options);
|
||
const accessToken = res && res.accessToken ? res.accessToken : '';
|
||
if (accessToken) return accessToken
|
||
return Promise.reject({ message: res && res.subMsg ? res.subMsg : '获取token失败' });
|
||
}
|
||
catch (e) {
|
||
return Promise.reject({ message: e.message || '获取token失败' });
|
||
}
|
||
}
|
||
/**
|
||
* 获取用户信息
|
||
* @param {obj} param0
|
||
*/
|
||
static async userInfo(auth_token) {
|
||
try {
|
||
let res = await alipaySdk.exec("alipay.user.info.share", { auth_token }, {});
|
||
if (res && res.code === '10000') {
|
||
const { avatar, certNo, mobile, userName, userId } = res;
|
||
return { avatar, certNo, mobile, userName, userId };
|
||
}
|
||
return Promise.reject({ message: res && res.subMsg ? res.subMsg : '获取用户信息失败' });
|
||
}
|
||
catch (e) {
|
||
return Promise.reject({ message: e.message || '获取用户信息失败' });
|
||
}
|
||
}
|
||
/**
|
||
* 创建支付宝交易订单
|
||
* @param {Object} params - 订单参数
|
||
* @param {String} params.outTradeNo - 商户订单号,必填
|
||
* @param {String} params.totalAmount - 订单总金额,单位为元,精确到小数点后两位,必填
|
||
* @param {String} params.subject - 订单标题,必填
|
||
* @param {String} params.buyerId - 买家支付宝用户ID,小程序场景下必填
|
||
* @param {String} params.timeExpire - 订单绝对超时时间 【示例值】2021-12-31 10:05:00
|
||
*/
|
||
static async createTrade({ outTradeNo, totalAmount, subject, buyerId, timeExpire }) {
|
||
try {
|
||
// 参数校验
|
||
if (!outTradeNo) {
|
||
return Promise.reject({ message: '商户订单号不能为空' });
|
||
}
|
||
if (!totalAmount) {
|
||
return Promise.reject({ message: '订单总金额不能为空' });
|
||
}
|
||
if (!subject) {
|
||
return Promise.reject({ message: '订单标题不能为空' });
|
||
}
|
||
if (!buyerId) {
|
||
return Promise.reject({ message: '买家支付宝用户ID不能为空' });
|
||
}
|
||
|
||
// 构建请求参数
|
||
let bizContent = {
|
||
out_trade_no: outTradeNo,
|
||
total_amount: totalAmount,
|
||
subject: subject,
|
||
buyer_id: buyerId,
|
||
product_code: 'JSAPI_PAY',
|
||
time_expire: timeExpire,
|
||
op_app_id: AlipaySdkConfig.appId,
|
||
};
|
||
|
||
let res = await alipaySdk.exec("alipay.trade.create", { notifyUrl, bizContent });
|
||
console.log('支付宝创建交易订单响应===')
|
||
console.log(res)
|
||
console.log('notifyUrl', notifyUrl)
|
||
// 检查响应结果
|
||
if (res && res.code === '10000') {
|
||
// 返回交易号
|
||
return {
|
||
notifyUrl,
|
||
appId: AlipaySdkConfig.appId,
|
||
tradeNo: res.tradeNo, // 支付宝交易号
|
||
outTradeNo: res.outTradeNo, // 商户订单号
|
||
};
|
||
}
|
||
|
||
// 返回错误信息
|
||
return Promise.reject({
|
||
message: res && res.subMsg ? res.subMsg : '创建交易失败',
|
||
code: res && res.code ? res.code : '',
|
||
});
|
||
} catch (e) {
|
||
return Promise.reject({ message: `创建交易失败: ${e.message}` });
|
||
}
|
||
}
|
||
|
||
static async queryTrade(trade_no) {
|
||
try {
|
||
let res = await alipaySdk.exec("alipay.trade.query", { bizContent: { trade_no } });
|
||
if (res && res.code === '10000') {
|
||
return res
|
||
}
|
||
return Promise.reject({
|
||
message: res && res.subMsg ? res.subMsg : '创建交易失败',
|
||
code: res && res.code ? res.code : '',
|
||
});
|
||
} catch (e) {
|
||
return Promise.reject({ message: `查询交易失败: ${e.message}` });
|
||
}
|
||
}
|
||
/**
|
||
* 解析支付宝支付成功回调
|
||
* @param {Object} notifyData - 支付宝回调数据(可以是 req.body 或 req.query)
|
||
* @returns {Object} 解析后的回调数据
|
||
* @returns {String} outTradeNo - 商户订单号
|
||
* @returns {String} tradeNo - 支付宝交易号
|
||
* @returns {String} tradeStatus - 交易状态
|
||
* @returns {String} totalAmount - 订单总金额
|
||
* @returns {String} buyerId - 买家支付宝用户ID
|
||
* @returns {String} gmtPayment - 支付时间
|
||
*/
|
||
static parsePayNotify(notifyData) {
|
||
try {
|
||
// 如果 notifyData 是对象,直接使用;如果是数组,取第一个元素
|
||
const params = notifyData && typeof notifyData === 'object' ? notifyData : {};
|
||
|
||
// 验证签名
|
||
// 支付宝SDK的签名验证方法可能因版本而异
|
||
// 尝试使用 checkNotifySign 方法验证签名,如果不存在则使用 verify 方法
|
||
let signVerified = false;
|
||
if (typeof alipaySdk.checkNotifySign === 'function') {
|
||
signVerified = alipaySdk.checkNotifySign(params, AlipaySdkConfig.alipayPublicKey);
|
||
} else if (typeof alipaySdk.verify === 'function') {
|
||
signVerified = alipaySdk.verify(params, AlipaySdkConfig.alipayPublicKey);
|
||
} else if (typeof alipay.checkNotifySign === 'function') {
|
||
// 尝试使用静态方法
|
||
signVerified = alipay.checkNotifySign(params, AlipaySdkConfig.alipayPublicKey);
|
||
} else {
|
||
// 如果SDK没有提供验证方法,记录警告但继续处理(生产环境建议实现签名验证)
|
||
console.warn('警告:支付宝SDK未找到签名验证方法,请确保实现签名验证逻辑');
|
||
}
|
||
|
||
if (!signVerified) {
|
||
return Promise.reject({ message: '签名验证失败', verified: false });
|
||
}
|
||
|
||
// 解析回调数据
|
||
const result = {
|
||
outTradeNo: params.out_trade_no || params.outTradeNo, // 商户订单号
|
||
tradeNo: params.trade_no || params.tradeNo, // 支付宝交易号
|
||
tradeStatus: params.trade_status || params.tradeStatus, // 交易状态
|
||
totalAmount: params.total_amount || params.totalAmount, // 订单总金额
|
||
buyerId: params.buyer_id || params.buyerId, // 买家支付宝用户ID
|
||
buyerLogonId: params.buyer_logon_id || params.buyerLogonId, // 买家支付宝账号
|
||
sellerId: params.seller_id || params.sellerId, // 卖家支付宝用户ID
|
||
sellerEmail: params.seller_email || params.sellerEmail, // 卖家支付宝账号
|
||
gmtCreate: params.gmt_create || params.gmtCreate, // 交易创建时间
|
||
gmtPayment: params.gmt_payment || params.gmtPayment, // 交易支付时间
|
||
gmtClose: params.gmt_close || params.gmtClose, // 交易关闭时间
|
||
subject: params.subject, // 订单标题
|
||
body: params.body, // 订单描述
|
||
receiptAmount: params.receipt_amount || params.receiptAmount, // 实收金额
|
||
invoiceAmount: params.invoice_amount || params.invoiceAmount, // 开票金额
|
||
pointAmount: params.point_amount || params.pointAmount, // 集分宝金额
|
||
fundBillList: params.fund_bill_list || params.fundBillList, // 支付金额信息
|
||
charset: params.charset, // 编码格式
|
||
notifyId: params.notify_id || params.notifyId, // 通知校验ID
|
||
notifyType: params.notify_type || params.notifyType, // 通知类型
|
||
notifyTime: params.notify_time || params.notifyTime, // 通知时间
|
||
version: params.version, // 接口版本
|
||
signType: params.sign_type || params.signType, // 签名类型
|
||
sign: params.sign, // 签名
|
||
appId: params.app_id || params.appId, // 支付宝分配给开发者的应用Id
|
||
verified: true, // 签名验证通过标识
|
||
};
|
||
|
||
// 检查交易状态
|
||
const tradeStatus = result.tradeStatus;
|
||
if (tradeStatus === 'TRADE_SUCCESS' || tradeStatus === 'TRADE_FINISHED') {
|
||
result.isSuccess = true;
|
||
} else {
|
||
result.isSuccess = false;
|
||
}
|
||
|
||
return result;
|
||
} catch (e) {
|
||
return Promise.reject({
|
||
message: `解析支付回调失败: ${e.message}`,
|
||
verified: false,
|
||
error: e
|
||
});
|
||
}
|
||
}
|
||
|
||
static parseRefundNotify(notifyData) {
|
||
try {
|
||
const params = notifyData && typeof notifyData === 'object' ? notifyData : {};
|
||
let signVerified = false;
|
||
if (typeof alipaySdk.checkNotifySign === 'function') {
|
||
signVerified = alipaySdk.checkNotifySign(params, AlipaySdkConfig.alipayPublicKey);
|
||
} else if (typeof alipaySdk.verify === 'function') {
|
||
signVerified = alipaySdk.verify(params, AlipaySdkConfig.alipayPublicKey);
|
||
} else if (typeof alipay.checkNotifySign === 'function') {
|
||
signVerified = alipay.checkNotifySign(params, AlipaySdkConfig.alipayPublicKey);
|
||
} else {
|
||
console.warn('警告:支付宝SDK未找到签名验证方法,请确保实现签名验证逻辑');
|
||
}
|
||
if (!signVerified) {
|
||
return Promise.reject({ message: '签名验证失败', verified: false });
|
||
}
|
||
return params;
|
||
} catch (e) {
|
||
return Promise.reject({ message: `解析退款回调失败: ${e.message}` });
|
||
}
|
||
}
|
||
|
||
static async refundTrade({ tradeNo, totalAmount: refundAmount, refundReason }) {
|
||
try {
|
||
let res = await alipaySdk.exec("alipay.trade.refund", {
|
||
bizContent: {
|
||
refund_amount: refundAmount,
|
||
trade_no: tradeNo,
|
||
refund_reason: refundReason
|
||
}
|
||
});
|
||
if (res && res.code === '10000') {
|
||
return res
|
||
}
|
||
return Promise.reject({
|
||
message: res && res.subMsg ? res.subMsg : '退款失败',
|
||
code: res && res.code ? res.code : '',
|
||
});
|
||
} catch (e) {
|
||
return Promise.reject({ message: `退款失败: ${e.message}` });
|
||
}
|
||
}
|
||
|
||
static async queryRefundDetail(trade_no, out_request_no) {
|
||
try {
|
||
let res = await alipaySdk.exec("alipay.trade.fastpay.refund.query", { bizContent: { trade_no, out_request_no, query_options: ['gmt_refund_pay'] } });
|
||
if (res && res.code === '10000') {
|
||
return { success: true, data: res }
|
||
}
|
||
return { success: false, message: res && res.subMsg ? res.subMsg : '查询退款失败', data: res };
|
||
} catch (e) {
|
||
return Promise.reject({ message: `查询退款详情失败: ${e.message}` });
|
||
}
|
||
}
|
||
};
|
||
|
||
module.exports = aliplayApi; |