hn-hlw-service/alipayApi/minialiplay.js

278 lines
11 KiB
JavaScript
Raw Normal View History

2026-07-27 11:28:33 +08:00
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;