/* * @Author: Targaryen * @Date: 2017-01-03 17:42:41 * @Last Modified by: Targaryen * @Last Modified time: 2017-04-20 21:01:44 */ 'use strict'; const config = global.yoho.config; const WxPayConfig = config.WxPayConfig; const _ = require('lodash'); const logger = global.yoho.logger; const rp = require('request-promise'); const Promise = require('bluebird'); const co = Promise.coroutine; const sign = require('./sign'); const md5 = require('yoho-md5'); const moment = require('moment'); const common = require('./common'); /** * 微信支付相关工具类 */ const tools = { /** * 拼接签名字符串 */ toUrlParams(urlObj) { let buff = ''; _.forEach(urlObj, (value, key) => { if (key !== 'sign') { buff += key + '=' + value + '&'; } }); buff = _.trimEnd(buff, '&'); return buff; }, /** * 构造获取code的url连接 */ createOauthUrlForCode(redirectUrl) { let urlObj = { appid: WxPayConfig.appId, redirect_uri: redirectUrl, response_type: 'code', scope: 'snsapi_base', state: 'STATE#wechat_redirect', }; let bizString = tools.toUrlParams(urlObj); return 'https://open.weixin.qq.com/connect/oauth2/authorize?' + bizString; }, /** * 构造获取open和access_toke的url地址 */ createOauthUrlForOpenid(code) { let urlObj = { appid: WxPayConfig.appId, secret: WxPayConfig.appSecret, code: code, grant_type: 'authorization_code' }; let bizString = tools.toUrlParams(urlObj); return 'https://api.weixin.qq.com/sns/oauth2/access_token?' + bizString; }, /** * 通过code从工作平台获取openid机器access_token */ getOpenidFromMp(code) { let uri = tools.createOauthUrlForOpenid(code); let rpOption = { method: 'POST', uri: uri, body: { some: 'payload' }, json: true }; return rp(rpOption).then(resultFromWx => { return resultFromWx && resultFromWx.openid; }).catch(err => { logger.error(err); }); }, /** * 微信统一下单接口 */ unifiedOrder(params) { let unifiedParams = { appid: WxPayConfig.appId, mch_id: WxPayConfig.mchId, notify_url: WxPayConfig.notifyUrl, device_info: 'WEB', nonce_str: common.nonceStr(), body: '有货订单号:' + params.orderCode, out_trade_no: 'YOHOBuy_' + params.orderCode, total_fee: Math.round(params.totalFee * 100), trade_type: 'JSAPI', time_start: moment().format('YYYYMMDDHHmmss'), time_expire: moment().add(2, 'hours').format('YYYYMMDDHHmmss'), spbill_create_ip: params.ip, openid: params.openId, sign_type: 'MD5' }; let signStr = md5(sign.raw(unifiedParams) + '&key=' + WxPayConfig.key).toUpperCase(); _.assign(unifiedParams, { sign: signStr }); let xml = common.toXml(unifiedParams); let xmlParams = { method: 'POST', uri: 'https://api.mch.weixin.qq.com/pay/unifiedorder', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: xml, timeout: 5000 }; return co(function* () { let xmlResult = yield rp(xmlParams); let jsonResult = yield common.xml2Obj(xmlResult); return jsonResult && jsonResult.xml; })(); } }; // TODO 微信支付 const Wechat = { /** * 支付中心微信支付相关处理 */ getOpenid(code, originalUrl) { if (!code) { let isProduction = process.env.NODE_ENV === 'production'; let baseUrl = (isProduction ? 'https://m.yohobuy.com' : 'http://m.yohobuy.com') + originalUrl; let redirectUrl = tools.createOauthUrlForCode(baseUrl); logger.info('payCenter: wechat pay no code'); return Promise.resolve({ redirectUrl: redirectUrl }); } else { return tools.getOpenidFromMp(code).then(openid => { return { openid: openid }; }); } }, /** * 异步拉起微信支付相关处理 */ pay(user, order, openId, ip) { return co(function* () { let unifiedOrderResult = yield tools.unifiedOrder({ orderCode: order.order_code, totalFee: parseFloat(order.payment_amount), openId: openId, ip: ip }); if (unifiedOrderResult && unifiedOrderResult.appid && unifiedOrderResult.prepay_id) { let nonceStr = common.nonceStr(); let resParams = { appId: unifiedOrderResult.appid, timeStamp: parseInt(Date.parse(new Date()) / 1000, 10) + '', nonceStr: nonceStr, package: 'prepay_id=' + unifiedOrderResult.prepay_id, signType: 'MD5', }; let paySign = md5(sign.raw(resParams) + '&key=' + WxPayConfig.key).toUpperCase(); _.assign(resParams, { paySign: paySign }); return { code: 200, data: { jsApiParameters: resParams } }; } else { logger.info('payCenter: wechat pay no unifiedOrderResult'); return {}; } })(); } }; module.exports = Wechat;