Authored by 姜枫

完成下单签名

... ... @@ -5,6 +5,7 @@
*/
'use strict';
const moment = require('moment');
const xml2js = require('xml2js');
const common = {
getPayExpireMin(expire) {
... ... @@ -23,6 +24,49 @@ const common = {
} else {
return defaultValue;
}
},
getPayExpireCouple(expire) {
let start = expire ? moment(expire, 'YYYY-MM-DD HH:mm:ss') : moment();
let end = expire ? moment(expire, 'YYYY-MM-DD HH:mm:ss') : moment();
return {
start: start.subtract(2, 'hours'),
end: end.add(5, 'minutes')
};
},
nonceStr(length) {
length = length || 32;
let chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
let str = '';
for (let i = 0; i < length; i++) {
str += chars[parseInt(Math.random() * length, 10)];
}
return str;
},
toXml(obj, root) {
let xmlBuilder = new xml2js.Builder({
rootName: root || 'xml'
});
return xmlBuilder.buildObject(obj);
},
xml2Obj(xml) {
let xmlParser = new xml2js.Parser({
trim: true,
explicitArray: false
});
return new Promise((resolve, reject) => {
xmlParser.parseString(xml, (err, result) => {
if (err) {
reject(err);
} else {
resolve(result);
}
});
});
}
};
... ...
... ... @@ -12,7 +12,7 @@ const Sign = {
keys = keys.sort();
return keys.map(k => {
return k.toLowerCase() + '=' + args[k];
return k + '=' + args[k];
}).join('&');
},
... ...
... ... @@ -5,3 +5,103 @@
*/
'use strict';
const moment = require('moment');
const rq = require('request-promise');
const common = require('./common');
const sign = require('./sign');
const md5 = require('md5');
const _ = require('lodash');
const logger = global.yoho.logger;
const config = global.yoho.config;
const wechatUnifiedOrderUrl = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
const Wechat = {
pay(user, order, info) {
let expire = common.getPayExpireCouple(order.payExpire);
info = JSON.parse(info.payParams || '{}');
let unifiedOrder = {
body: 'BLK订单号:' + order.orderCode,
out_trade_no: order.orderCode,
total_fee: parseInt(order.paymentAmount * 100, 10),
time_start: moment(expire.start).format('YYYYMMDDHHmmss'),
time_expire: moment(expire.end).format('YYYYMMDDHHmmss'),
trade_type: 'NATIVE',
product_id: order.orderCode,
notify_url: config.pay.serviceNotify + 'payment/weixin_notify',
appid: info.app_id,
mch_id: info.partner_id,
nonce_str: common.nonceStr()
};
let signStr = md5(sign.raw(unifiedOrder) + '&key=' + info.partner_key);
unifiedOrder.sign = _.toUpper(signStr);
return this.unifiedOrder(unifiedOrder).then(result => {
console.log(result);
if (result && result.xml) {
let data = result.xml || {};
if (data.return_code === 'SUCCESS' && Wechat.checkSign(data, info)) {
return {
code: 200,
data: {
href: data.code_url
}
};
}
}
return {
code: 400,
message: '请稍后重试'
};
});
},
unifiedOrder(unifiedOrder) {
let xml = common.toXml(unifiedOrder);
return rq({
method: 'POST',
uri: wechatUnifiedOrderUrl,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': Buffer.byteLength(xml)
},
body: xml,
timeout: 1000
}).then(result => {
console.log(result);
if (result) {
return common.xml2Obj(result);
} else {
return {};
}
}).catch(err => {
logger.error(`call wechat pay unifiedOrder fail. order=${JSON.stringify(unifiedOrder)}`, err);
return {};
});
},
notify(data, info) { // eslint-disable-line
},
checkSign(data, info) {
if (data && data.sign) {
let signStr = data.sign || '';
delete data.sign;
return signStr === md5(sign.raw(data) + info.partner_key);
}
return false;
}
};
module.exports = Wechat;
... ...
... ... @@ -10,6 +10,7 @@
const PayData = require('../models/pay');
const OrderData = require('../models/order');
const Alipay = require('./pay/alipay');
const Wechat = require('./pay/wechat');
const Promise = require('bluebird');
const co = Promise.coroutine;
const logger = global.yoho.logger;
... ... @@ -26,6 +27,8 @@ const Payment = {
if (payInfo && payInfo.id === method) {
if (method === PayData.payments.alipay) {
result = Alipay.pay(user, order, payInfo);
} else if (method === PayData.payments.wechat) {
result = yield Wechat.pay(user, order, payInfo);
}
}
... ... @@ -83,11 +86,13 @@ const Payment = {
if (payId === PayData.payments.alipay) {
payResult = Alipay.notify(query, payInfo);
payResult.bankName = payResult.bankName || payInfo.payName || '';
payResult.bankCode = payResult.bankCode || payInfo.pay_code || '';
} else if (payId === PayData.payments.wechat) {
payResult = Wechat.notify(query, payInfo);
}
payResult.bankName = payResult.bankName || payInfo.payName || '';
payResult.bankCode = payResult.bankCode || payInfo.pay_code || '';
if (payResult && payResult.payResult === 200) {
if (payResult.orderCode) {
logger.info('pay back confirm');
... ...
... ... @@ -18,7 +18,8 @@ const logger = global.yoho.logger;
const _ = require('lodash');
const payments = {
alipay: 33
alipay: 33,
wechat: 34
};
/**
... ... @@ -32,7 +33,7 @@ const getOnlinePayProvider = () => {
}
let online = _(result.data)
.filter(i => _.includes([payments.alipay], i.id))
.filter(i => _.includes(_.values(payments), i.id))
.map(i => {
return {
id: i.id,
... ...
{
"name": "yoho-blk",
"version": "0.0.1",
"private": true,
"description": "A New Yohoblk Project With Express",
"repository": {
"type": "git",
"url": "http://git.yoho.cn/fe/yoho-blk.git"
},
"scripts": {
"start": "node app.js",
"dev": "nodemon -e js,hbs -i public/ app.js",
"online": "NODE_ENV=\"production\" node app.js",
"debug": "DEBUG=\"express:*\" nodemon -e js,hbs -i public/ app.js",
"lint-js": "eslint -c .eslintrc --cache --fix .",
"lint-css": "stylelint --config .stylelintrc public/scss/**/*.css",
"precommit": "node lint.js",
"test": "NODE_ENV=test nyc ./node_modules/.bin/ava",
"posttest": "nyc report --reporter=html"
},
"ava": {
"tap": true,
"require": [
"babel-register"
],
"babel": {
"presets": [
"es2015"
]
}
},
"license": "MIT",
"dependencies": {
"bluebird": "^3.4.0",
"body-parser": "^1.15.0",
"captchapng": "0.0.1",
"connect-memcached": "^0.2.0",
"connect-multiparty": "^2.0.0",
"cookie-parser": "^1.4.3",
"csurf": "^1.9.0",
"express": "^4.13.1",
"express-handlebars": "^3.0.0",
"express-session": "^1.13.0",
"influxdb-winston": "^1.0.1",
"lodash": "^4.13.1",
"md5": "^2.1.0",
"memcached": "^2.2.2",
"moment": "^2.13.0",
"morgan": "^1.7.0",
"oneapm": "^1.2.20",
"passport": "^0.3.2",
"passport-douban": "0.0.1",
"passport-local": "^1.0.0",
"passport-qq": "0.0.3",
"passport-renren": "^0.1.3",
"passport-sina": "^0.1.0",
"passport-strategy": "1.x.x",
"passport-weixin": "^0.1.0",
"request": "^2.73.0",
"request-promise": "^3.0.0",
"serve-favicon": "^2.3.0",
"uuid": "^2.0.2",
"winston": "^2.2.0",
"winston-daily-rotate-file": "^1.1.4",
"xss": "^0.2.13",
"yoho-node-lib": "0.0.45"
},
"devDependencies": {
"autoprefixer": "^6.3.6",
"ava": "^0.15.2",
"babel-preset-es2015": "^6.9.0",
"babel-register": "^6.9.0",
"eslint": "^2.12.0",
"eslint-config-yoho": "^1.0.1",
"gulp": "^3.9.1",
"gulp-cssnano": "^2.1.2",
"gulp-ftp": "^1.1.0",
"gulp-postcss": "^6.1.0",
"gulp-sourcemaps": "^2.0.0-alpha",
"gulp-util": "^3.0.7",
"handlebars-loader": "^1.3.0",
"husky": "^0.11.4",
"nodemon": "1.9.2",
"nyc": "^6.6.1",
"postcss-assets": "^4.0.1",
"postcss-cachebuster": "^0.1.3",
"postcss-calc": "^5.2.1",
"postcss-center": "^1.0.0",
"postcss-clearfix": "^1.0.0",
"postcss-crip": "^2.0.0",
"postcss-opacity": "^3.0.0",
"postcss-position": "^0.5.0",
"postcss-pxtorem": "^3.3.1",
"postcss-short": "^1.4.0",
"postcss-sprites": "^3.1.2",
"postcss-use": "^2.0.2",
"precss": "^1.4.0",
"rewire": "^2.5.1",
"shelljs": "^0.7.0",
"stylelint": "^7.1.0",
"stylelint-config-yoho": "^1.2.7",
"webpack": "^1.13.1",
"webpack-dev-server": "^1.14.1",
"webpack-stream": "^3.1.0",
"yoho-eventproxy": "^0.3.6",
"yoho-handlebars": "^4.0.5",
"yoho-jquery": "^1.12.4",
"yoho-jquery-accordion": "0.0.2",
"yoho-jquery-dotdotdot": "0.0.1",
"yoho-jquery-lazyload": "^1.9.7",
"yoho-jquery-nanoscroller": "0.0.1",
"yoho-jquery-placeholder": "^2.3.1",
"yoho-jquery-qrcode": "0.0.3",
"yoho-json2": "^1.0.0",
"yoho-slider": "0.0.2"
}
}
{
"name": "yoho-blk",
"version": "0.0.1",
"private": true,
"description": "A New Yohoblk Project With Express",
"repository": {
"type": "git",
"url": "http://git.yoho.cn/fe/yoho-blk.git"
},
"scripts": {
"start": "node app.js",
"dev": "nodemon -e js,hbs -i public/ app.js",
"online": "NODE_ENV=\"production\" node app.js",
"debug": "DEBUG=\"express:*\" nodemon -e js,hbs -i public/ app.js",
"lint-js": "eslint -c .eslintrc --cache --fix .",
"lint-css": "stylelint --config .stylelintrc public/scss/**/*.css",
"precommit": "node lint.js",
"test": "NODE_ENV=test nyc ./node_modules/.bin/ava",
"posttest": "nyc report --reporter=html"
},
"ava": {
"tap": true,
"require": [
"babel-register"
],
"babel": {
"presets": [
"es2015"
]
}
},
"license": "MIT",
"dependencies": {
"bluebird": "^3.4.0",
"body-parser": "^1.15.0",
"captchapng": "0.0.1",
"connect-memcached": "^0.2.0",
"connect-multiparty": "^2.0.0",
"cookie-parser": "^1.4.3",
"csurf": "^1.9.0",
"express": "^4.13.1",
"express-handlebars": "^3.0.0",
"express-session": "^1.13.0",
"influxdb-winston": "^1.0.1",
"lodash": "^4.13.1",
"md5": "^2.1.0",
"memcached": "^2.2.2",
"moment": "^2.13.0",
"morgan": "^1.7.0",
"oneapm": "^1.2.20",
"passport": "^0.3.2",
"passport-douban": "0.0.1",
"passport-local": "^1.0.0",
"passport-qq": "0.0.3",
"passport-renren": "^0.1.3",
"passport-sina": "^0.1.0",
"passport-strategy": "1.x.x",
"passport-weixin": "^0.1.0",
"request": "^2.73.0",
"request-promise": "^3.0.0",
"serve-favicon": "^2.3.0",
"uuid": "^2.0.2",
"winston": "^2.2.0",
"winston-daily-rotate-file": "^1.1.4",
"xml2js": "^0.4.17",
"xss": "^0.2.13",
"yoho-node-lib": "0.0.45"
},
"devDependencies": {
"autoprefixer": "^6.3.6",
"ava": "^0.15.2",
"babel-preset-es2015": "^6.9.0",
"babel-register": "^6.9.0",
"eslint": "^2.12.0",
"eslint-config-yoho": "^1.0.1",
"gulp": "^3.9.1",
"gulp-cssnano": "^2.1.2",
"gulp-ftp": "^1.1.0",
"gulp-postcss": "^6.1.0",
"gulp-sourcemaps": "^2.0.0-alpha",
"gulp-util": "^3.0.7",
"handlebars-loader": "^1.3.0",
"husky": "^0.11.4",
"nodemon": "1.9.2",
"nyc": "^6.6.1",
"postcss-assets": "^4.0.1",
"postcss-cachebuster": "^0.1.3",
"postcss-calc": "^5.2.1",
"postcss-center": "^1.0.0",
"postcss-clearfix": "^1.0.0",
"postcss-crip": "^2.0.0",
"postcss-opacity": "^3.0.0",
"postcss-position": "^0.5.0",
"postcss-pxtorem": "^3.3.1",
"postcss-short": "^1.4.0",
"postcss-sprites": "^3.1.2",
"postcss-use": "^2.0.2",
"precss": "^1.4.0",
"rewire": "^2.5.1",
"shelljs": "^0.7.0",
"stylelint": "^7.1.0",
"stylelint-config-yoho": "^1.2.7",
"webpack": "^1.13.1",
"webpack-dev-server": "^1.14.1",
"webpack-stream": "^3.1.0",
"yoho-eventproxy": "^0.3.6",
"yoho-handlebars": "^4.0.5",
"yoho-jquery": "^1.12.4",
"yoho-jquery-accordion": "0.0.2",
"yoho-jquery-dotdotdot": "0.0.1",
"yoho-jquery-lazyload": "^1.9.7",
"yoho-jquery-nanoscroller": "0.0.1",
"yoho-jquery-placeholder": "^2.3.1",
"yoho-jquery-qrcode": "0.0.3",
"yoho-json2": "^1.0.0",
"yoho-slider": "0.0.2"
}
}
... ...