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;