UNPKG

xx-weixin-pay

Version:
232 lines (184 loc) 6.32 kB
const util = require('./util'); const request = require('request'); const md5 = require('MD5'); exports = module.exports = exports.default = WXPay; function WXPay () { if (!(this instanceof WXPay)) { return new WXPay(arguments[0]); } this.options = arguments[0]; this.wxpayID = { appid: this.options.appid, mch_id: this.options.mch_id }; } WXPay.mix = function () { switch (arguments.length) { case 1: const obj = arguments[0]; for (const key in obj) { if (WXPay.prototype.hasOwnProperty(key)) { throw new Error('Prototype method exist. method: ' + key); } WXPay.prototype[key] = obj[key]; } break; case 2: const key = arguments[0].toString(), fn = arguments[1]; if (WXPay.prototype.hasOwnProperty(key)) { throw new Error('Prototype method exist. method: ' + key); } WXPay.prototype[key] = fn; break; } }; WXPay.mix('option', function (option) { for (const k in option) { this.options[k] = option[k]; } }); WXPay.mix('sign', function (param) { const querystring = Object.keys(param).filter(function (key) { return param[key] !== undefined && param[key] !== '' && ['pfx', 'partner_key', 'sign', 'key'].indexOf(key) < 0; }).sort().map(function (key) { return key + '=' + param[key]; }).join("&") + "&key=" + this.options.partner_key; return md5(querystring).toUpperCase(); }); WXPay.mix('createUnifiedOrder', function (opts, fn) { opts.nonce_str = opts.nonce_str || util.generateNonceString(); util.mix(opts, this.wxpayID); opts.sign = this.sign(opts); request({ url: `https://api.mch.weixin.qq.com${this.options.sandbox ? '/sandboxnew' : ''}/pay/unifiedorder`, method: 'POST', body: util.buildXML(opts), agentOptions: { pfx: this.options.pfx, passphrase: this.options.mch_id } }, function (err, response, body) { util.parseXML(body, fn); }); }); WXPay.mix('getBrandWCPayRequestParams', function (order, fn) { order.trade_type = "JSAPI"; const _this = this; this.createUnifiedOrder(order, function (err, data) { const reqparam = { appId: _this.options.appid, timeStamp: Math.floor(Date.now() / 1000) + "", nonceStr: data.nonce_str, package: "prepay_id=" + data.prepay_id, signType: "MD5" }; reqparam.paySign = _this.sign(reqparam); fn(err, reqparam); }); }); WXPay.mix('createMerchantPrepayUrl', function (param) { param.time_stamp = param.time_stamp || Math.floor(Date.now() / 1000); param.nonce_str = param.nonce_str || util.generateNonceString(); util.mix(param, this.wxpayID); param.sign = this.sign(param); const query = Object.keys(param).filter(function (key) { return ['sign', 'mch_id', 'product_id', 'appid', 'time_stamp', 'nonce_str'].indexOf(key) >= 0; }).map(function (key) { return key + "=" + encodeURIComponent(param[key]); }).join('&'); return "weixin://wxpay/bizpayurl?" + query; }); WXPay.mix('useWXCallback', function (fn) { return function (req, res, next) { const _this = this; res.success = function () { res.end(util.buildXML({ xml: { return_code: 'SUCCESS' } })); }; res.fail = function () { res.end(util.buildXML({ xml: { return_code: 'FAIL' } })); }; util.pipe(req, function (err, data) { const xml = data.toString('utf8'); util.parseXML(xml, function (err, msg) { req.wxmessage = msg; fn.apply(_this, [msg, req, res, next]); }); }); }; }); WXPay.mix('queryOrder', function (query, fn) { if (!(query.transaction_id || query.out_trade_no)) { fn(null, { return_code: 'FAIL', return_msg: '缺少参数' }); } query.nonce_str = query.nonce_str || util.generateNonceString(); util.mix(query, this.wxpayID); query.sign = this.sign(query); request({ url: `https://api.mch.weixin.qq.com${this.options.sandbox ? '/sandboxnew' : ''}/pay/orderquery`, method: "POST", body: util.buildXML({ xml: query }) }, function (err, res, body) { util.parseXML(body, fn); }); }); WXPay.mix('closeOrder', function (order, fn) { if (!order.out_trade_no) { fn(null, { return_code: "FAIL", return_msg: "缺少参数" }); } order.nonce_str = order.nonce_str || util.generateNonceString(); util.mix(order, this.wxpayID); order.sign = this.sign(order); request({ url: `https://api.mch.weixin.qq.com${this.options.sandbox ? '/sandboxnew' : ''}/pay/closeorder`, method: "POST", body: util.buildXML({ xml: order }) }, function (err, res, body) { util.parseXML(body, fn); }); }); WXPay.mix('refund', function (order, fn) { if (!(order.transaction_id || order.out_refund_no)) { fn(null, { return_code: 'FAIL', return_msg: '缺少参数' }); } order.nonce_str = order.nonce_str || util.generateNonceString(); util.mix(order, this.wxpayID); order.sign = this.sign(order); request({ url: `https://api.mch.weixin.qq.com${this.options.sandbox ? '/sandboxnew' : ''}/secapi/pay/refund`, method: "POST", body: util.buildXML({ xml: order }), agentOptions: { pfx: this.options.pfx, passphrase: this.options.mch_id } }, function (err, response, body) { util.parseXML(body, fn); }); }); WXPay.mix('queryRefund', function (order, fn) { const { transaction_id, out_trade_no, out_refund_no, refund_id } = order; if (!(transaction_id || out_trade_no || out_refund_no || refund_id)) { fn(null, { return_code: 'FAIL', return_msg: '缺少参数' }); } order.nonce_str = order.nonce_str || util.generateNonceString(); util.mix(order, this.wxpayID); order.sign = this.sign(order); request({ url: `https://api.mch.weixin.qq.com${this.options.sandbox ? '/sandboxnew' : ''}/pay/refundquery`, method: "POST", body: util.buildXML({ xml: order }) }, function (err, res, body) { util.parseXML(body, fn); }); }); WXPay.mix('getSignKey', function (fn) { const data = { nonce_str: util.generateNonceString(), mch_id: this.options.mch_id, }; data.sign = this.sign(data); request({ url: 'https://api.mch.weixin.qq.com/sandboxnew/pay/getsignkey', method: 'post', body: util.buildXML({ xml: data }), }, function (err, res, body) { util.parseXML(body, fn); }); });