Authored by 郭成尧

pay-modified

  1 +/**
  2 + * TAR NOTE: 从 YOHO-BLK 项目复制,未针对本项目做适配
  3 + * @author: jiangfeng<jeff.jiang@yoho.cn>
  4 + * @date: 16/7/22
  5 + */
  6 +
  7 +'use strict';
  8 +
  9 +const config = global.yoho.config;
  10 +const helpers = global.yoho.helpers;
  11 +const common = require('./common');
  12 +const sign = require('./sign');
  13 +const payHelpersBank = require('./bank');
  14 +const md5 = require('md5');
  15 +const logger = global.yoho.logger;
  16 +
  17 +const ALIPAY_URL = 'https://mapi.alipay.com/gateway.do';
  18 +
  19 +const Alibank = {
  20 +
  21 + pay(user, order, param, protocol) {
  22 + let payParams = JSON.parse(param.payParams);
  23 + let extraParam = JSON.stringify({
  24 + sign_id_ext: user.uid,
  25 + defaultbank: param.bankCode || ''
  26 + });
  27 +
  28 + let params = {
  29 + service: 'create_direct_pay_by_user',
  30 + partner: payParams.merchant_id,
  31 + _input_charset: 'utf-8',
  32 + notify_url: config.pay.serviceNotify + 'payment/alipay_notify',
  33 + return_url: protocol + ':' + helpers.urlFormat('/shopping/pay/callback/alibank'),
  34 + subject: 'BLK订单号:' + order.order_code,
  35 + out_trade_no: order.order_code,
  36 + it_b_pay: common.getPayExpireMin(order.pay_expire) + 'm',
  37 + total_fee: order.payment_amount,
  38 + payment_type: '1',
  39 + defaultbank: param.bankCode,
  40 + seller_email: payParams.merchant_other_code,
  41 + extra_common_param: extraParam
  42 + };
  43 +
  44 + // TODO 防钓鱼配置,参考php
  45 +
  46 + let signStr = md5(sign.raw(params) + payParams.merchant_key);
  47 + let body = sign.rawUncode(params) + '&sign=' + signStr + '&sign_type=MD5';
  48 +
  49 + return {
  50 + code: 200,
  51 + data: {
  52 + href: ALIPAY_URL + '?' + body
  53 + }
  54 + };
  55 + },
  56 + notify(data, param) {
  57 + let payParams = param.payParams && JSON.parse(param.payParams) || {};
  58 + let orderCode = parseInt(data.out_trade_no, 10);
  59 + let extraParam = data.extra_common_param && JSON.parse(data.extra_common_param) || {};
  60 + let bankName = payHelpersBank.getList()[extraParam.defaultbank] &&
  61 + payHelpersBank.getList()[extraParam.defaultbank].name || '';
  62 +
  63 + logger.info(`Alibank notify, params = ${JSON.stringify(data)}`);
  64 +
  65 + if (!this.checkNotify(data, payParams)) {
  66 + return {payResult: -1, bankName: bankName};
  67 + } else {
  68 + return {
  69 + bankName: bankName,
  70 + orderCode: orderCode,
  71 + payResult: data.trade_status === 'TRADE_SUCCESS' ? 200 : 400,
  72 + payTime: data.gmt_payment || '',
  73 + totalFee: data.total_fee,
  74 + resultMsg: data.notify_type,
  75 + payOrderCode: orderCode,
  76 + tradeNo: data.trade_no,
  77 + bankBillNo: data.bank_seq_no || ''
  78 + };
  79 + }
  80 + },
  81 +
  82 + checkNotify(data, payParams) {
  83 + let signValue = data.sign;
  84 +
  85 + if (!payParams || !data) {
  86 + return false;
  87 + }
  88 +
  89 + delete data.sign;
  90 + delete data.sign_type;
  91 + delete data.code;
  92 +
  93 + let signStr = md5(sign.raw(data) + payParams.merchant_key);
  94 +
  95 + return signValue === signStr;
  96 + }
  97 +};
  98 +
  99 +module.exports = Alibank;
  1 +/**
  2 + * Created by TaoHuang on 2016/7/18.
  3 + */
  4 +'use strict';
  5 +
  6 +const Bank = {
  7 + getList() {
  8 + return {
  9 + BOCB2C: {
  10 + name: '中国银行',
  11 + ico: '//static.yohobuy.com/images/pay/icon/zhongguo.png'
  12 + },
  13 + ABC: {
  14 + name: '中国农业银行',
  15 + ico: '//static.yohobuy.com/images/pay/icon/nongye.png'
  16 + },
  17 + SPABANK: {
  18 + name: '平安银行',
  19 + ico: '//static.yohobuy.com/images/pay/icon/pingan.png'
  20 + },
  21 + CMBC: {
  22 + name: '中国民生银行',
  23 + ico: '//static.yohobuy.com/images/pay/icon/minsheng.png'
  24 + },
  25 + ICBCB2C: {
  26 + name: '中国工商银行',
  27 + ico: '//static.yohobuy.com/images/pay/icon/gongshang.png'
  28 + },
  29 + SPDB: {
  30 + name: '浦发银行',
  31 + ico: '//static.yohobuy.com/images/pay/icon/pufa.png'
  32 + },
  33 + BJRCB: {
  34 + name: '北京农商银行',
  35 + ico: '//static.yohobuy.com/images/pay/icon/beijingnongshang.png'
  36 + },
  37 + HZCBB2C: {
  38 + name: '杭州银行',
  39 + ico: '//static.yohobuy.com/images/pay/icon/hangzhou.png'
  40 + },
  41 + CMB: {
  42 + name: '招商银行',
  43 + ico: '//static.yohobuy.com/images/pay/icon/zhaoshang.png'
  44 + },
  45 + CIB: {
  46 + name: '兴业银行',
  47 + ico: '//static.yohobuy.com/images/pay/icon/xingye.png'
  48 + },
  49 + FDB: {
  50 + name: '富滇银行',
  51 + ico: '//static.yohobuy.com/images/pay/icon/fudian.png'
  52 + },
  53 + CEBDEBIT: {
  54 + name: '中国光大银行',
  55 + ico: '//static.yohobuy.com/images/pay/icon/guangda.png'
  56 + },
  57 + CCB: {
  58 + name: '中国建设银行',
  59 + ico: '//static.yohobuy.com/images/pay/icon/zhongguojianshe.png'
  60 + },
  61 + GDB: {
  62 + name: '广发银行',
  63 + ico: '//static.yohobuy.com/images/pay/icon/guangfa.png'
  64 + },
  65 + POSTGC: {
  66 + name: '中国邮政储蓄',
  67 + ico: '//static.yohobuy.com/images/pay/icon/zhongguoyouzhengchuxu.png'
  68 + },
  69 + SHBANK: {
  70 + name: '上海银行',
  71 + ico: '//static.yohobuy.com/images/pay/icon/shanghai.png'
  72 + },
  73 + NBBANK: {
  74 + name: '宁波银行',
  75 + ico: '//static.yohobuy.com/images/pay/icon/ningbo.png'
  76 + }
  77 + };
  78 + }
  79 +};
  80 +
  81 +module.exports = Bank;
1 /** 1 /**
2 * 各种支付的入口 2 * 各种支付的入口
3 - * 3 + * TAR NOTE: 本项目中仅支持支付宝和微信支付,其他支付方式需调试
4 * @author: jiangfeng<jeff.jiang@yoho.cn> 4 * @author: jiangfeng<jeff.jiang@yoho.cn>
5 * @date: 16/7/22 5 * @date: 16/7/22
6 */ 6 */
7 7
8 'use strict'; 8 'use strict';
9 9
10 -const PayData = require('../models/pay');  
11 -const OrderData = require('../models/order'); 10 +const PayModel = require('../models/pay');
12 const Alipay = require('./pay/alipay'); 11 const Alipay = require('./pay/alipay');
  12 +const Alibank = require('./pay/alibank');
13 const Wechat = require('./pay/wechat'); 13 const Wechat = require('./pay/wechat');
14 const Promise = require('bluebird'); 14 const Promise = require('bluebird');
15 const common = require('./pay/common'); 15 const common = require('./pay/common');
@@ -48,20 +48,25 @@ const Payment = { @@ -48,20 +48,25 @@ const Payment = {
48 48
49 let method = paymentPars[0] * 1; 49 let method = paymentPars[0] * 1;
50 50
51 - if (method === PayData.payments.wechat) { 51 + if (method === PayModel.payments.wechat) {
52 // 如果是微信支付,不需要调用获取支付方式详情接口 52 // 如果是微信支付,不需要调用获取支付方式详情接口
53 - result = yield Wechat.pay(user, order, { id: PayData.payments.wechat }); 53 + result = yield Wechat.pay(user, order, { id: PayModel.payments.wechat });
54 } else { 54 } else {
55 - payInfo = yield PayData.getPaymentInfo(method); 55 + payInfo = yield PayModel.getPaymentInfo(method);
56 56
57 if (!payInfo.payParams) { 57 if (!payInfo.payParams) {
58 return result; 58 return result;
59 } 59 }
60 60
61 switch (payInfo.id) { 61 switch (payInfo.id) {
62 - case PayData.payments.alipay: 62 + case PayModel.payments.alipay:
63 result = Alipay.pay(user, order, payInfo, protocol); 63 result = Alipay.pay(user, order, payInfo, protocol);
64 break; 64 break;
  65 + case PayModel.payments.alibank:
  66 + bankCode = paymentPars[1];
  67 + payInfo.bankCode = bankCode; // 设置默认银行
  68 + result = Alibank.pay(user, order, payInfo, protocol);
  69 + break;
65 default: 70 default:
66 break; 71 break;
67 } 72 }
@@ -83,8 +88,8 @@ const Payment = { @@ -83,8 +88,8 @@ const Payment = {
83 88
84 beforePay(user, order, method, bankCode) { 89 beforePay(user, order, method, bankCode) {
85 return Promise.all([ 90 return Promise.all([
86 - OrderData.updateOrderPayment(order.order_code, method, user.uid),  
87 - PayData.getBankByOrder(order.order_code) 91 + PayModel.updateOrderPayment(order.order_code, method, user.uid),
  92 + PayModel.getBankByOrder(order.order_code)
88 ]).then(result => { 93 ]).then(result => {
89 let paymentRecord = result[0]; 94 let paymentRecord = result[0];
90 let bankRecord = result[1]; 95 let bankRecord = result[1];
@@ -96,9 +101,9 @@ const Payment = { @@ -96,9 +101,9 @@ const Payment = {
96 } 101 }
97 102
98 if (bankRecord && bankRecord.bankCode) { 103 if (bankRecord && bankRecord.bankCode) {
99 - return PayData.updateOrderPayBank(order.order_code, method, bankCode); 104 + return PayModel.updateOrderPayBank(order.order_code, method, bankCode);
100 } else { 105 } else {
101 - return PayData.setOrderPayBank(order.order_code, method, bankCode); 106 + return PayModel.setOrderPayBank(order.order_code, method, bankCode);
102 } 107 }
103 108
104 }).catch(e => { 109 }).catch(e => {
@@ -111,23 +116,23 @@ const Payment = { @@ -111,23 +116,23 @@ const Payment = {
111 }); 116 });
112 }, 117 },
113 118
114 - afterPay(query, payId, user) { 119 + afterPay(query, payId, user, sessionKey) {
115 return co(function*() { 120 return co(function*() {
116 - let payInfo = yield PayData.getPaymentInfo(payId); 121 + let payInfo = yield PayModel.getPaymentInfo(payId);
117 let payResult = {}; 122 let payResult = {};
118 let payData = {}; 123 let payData = {};
119 let payName = ''; 124 let payName = '';
120 125
121 - if (payId === PayData.payments.alipay) { 126 + if (payId === PayModel.payments.alipay) {
122 payResult = Alipay.notify(query, payInfo); 127 payResult = Alipay.notify(query, payInfo);
123 - } else if (payId === PayData.payments.alibank) { 128 + } else if (payId === PayModel.payments.alibank) {
124 payResult = Alibank.notify(query, payInfo); 129 payResult = Alibank.notify(query, payInfo);
125 } 130 }
126 131
127 payResult.bankName = payName = payResult.bankName || payInfo.payName || ''; 132 payResult.bankName = payName = payResult.bankName || payInfo.payName || '';
128 payResult.bankCode = payResult.bankCode || payInfo.pay_code || ''; 133 payResult.bankCode = payResult.bankCode || payInfo.pay_code || '';
129 134
130 - //记录日志 135 + // 记录日志
131 logger.info(`\r\n\r\n pay back confirmreq = ${JSON.stringify({ 136 logger.info(`\r\n\r\n pay back confirmreq = ${JSON.stringify({
132 query: query, 137 query: query,
133 payId: payId, 138 payId: payId,
@@ -138,10 +143,10 @@ const Payment = { @@ -138,10 +143,10 @@ const Payment = {
138 if (payResult && payResult.payResult === 200) { 143 if (payResult && payResult.payResult === 200) {
139 if (payResult.orderCode) { 144 if (payResult.orderCode) {
140 logger.info('pay back confirm'); 145 logger.info('pay back confirm');
141 - yield PayData.sendPayConfirm(payResult.orderCode, payId, user.uid); 146 + yield PayModel.sendPayConfirm(payResult.orderCode, payId, user.uid);
142 } 147 }
143 148
144 - payData = yield PayData.procOrderData(payResult, user.uid); 149 + payData = yield PayModel.procOrderData(payResult, user.uid, sessionKey);
145 } else { 150 } else {
146 payData = { 151 payData = {
147 code: 500, 152 code: 500,
  1 +/**
  2 + * 支付相关api调用
  3 + * @author: jiangfeng<jeff.jiang@yoho.cn>
  4 + * @date: 2016/07/18
  5 + */
  6 +
  7 +'use strict';
  8 +
  9 +const api = global.yoho.API;
  10 +
  11 +// 获取支付宝等平台支付方式列表
  12 +const getPayProvider = () => {
  13 + return api.get('', {
  14 + method: 'web.SpaceOrders.getPaymentList'
  15 + }, {cache: true});
  16 +};
  17 +
  18 +// 获取单个支付方式相关详细信息
  19 +const getPaymentInfo = (id) => {
  20 + return api.get('', {
  21 + method: 'web.SpaceOrders.getPaymentById',
  22 + id: id
  23 + }, {cache: true});
  24 +};
  25 +
  26 +/* 获取上次使用的支付方式*/
  27 +const getBankByOrder = (code) => {
  28 + return api.get('', {
  29 + method: 'web.SpaceOrders.getOrderPayBank',
  30 + orderCode: code
  31 + });
  32 +};
  33 +
  34 +/* 记录支付方式*/
  35 +const setOrderPayBank = (code, payment, bankCode) => {
  36 + return api.get('', {
  37 + method: 'web.SpaceOrders.addOrderPayBank',
  38 + orderCode: code,
  39 + payment: payment,
  40 + bankCode: bankCode
  41 + });
  42 +};
  43 +
  44 +/* 更改支付方式*/
  45 +const updateOrderPayBank = (code, payment, bankCode) => {
  46 + return api.get('', {
  47 + method: 'web.SpaceOrders.modifyOrderPayBank',
  48 + orderCode: code,
  49 + payment: payment,
  50 + bankCode: bankCode
  51 + });
  52 +};
  53 +
  54 +/* 发送支付确认*/
  55 +const sendPayConfirm = (code, payment, uid) => {
  56 + return api.get('', {
  57 + method: 'app.SpaceOrders.payConfirm',
  58 + order_code: code,
  59 + payment_id: payment,
  60 + uid: uid
  61 + });
  62 +};
  63 +
  64 +const sendMessage = (mobile, template, codes) => {
  65 + return api.get('', {
  66 + method: 'app.message.sendMsg',
  67 + mobile: mobile,
  68 + template: template,
  69 + codes: codes
  70 + });
  71 +};
  72 +
  73 +module.exports = {
  74 + getPayProvider,
  75 + getPaymentInfo,
  76 + getBankByOrder,
  77 + setOrderPayBank,
  78 + updateOrderPayBank,
  79 + sendPayConfirm,
  80 + sendMessage
  81 +};
@@ -10,8 +10,11 @@ const api = global.yoho.API; @@ -10,8 +10,11 @@ const api = global.yoho.API;
10 const serviceAPI = global.yoho.ServiceAPI; 10 const serviceAPI = global.yoho.ServiceAPI;
11 const utils = '../../../utils'; 11 const utils = '../../../utils';
12 const productProcess = require(`${utils}/product-process`); 12 const productProcess = require(`${utils}/product-process`);
  13 +const payApi = require('./pay-api');
13 const helpers = global.yoho.helpers; 14 const helpers = global.yoho.helpers;
14 const _ = require('lodash'); 15 const _ = require('lodash');
  16 +const co = require('bluebird').coroutine;
  17 +const logger = global.yoho.logger;
15 18
16 // 资源位 19 // 资源位
17 const _getBanner = (param) => { 20 const _getBanner = (param) => {
@@ -75,7 +78,7 @@ const _getOthersBuy = (param) => { @@ -75,7 +78,7 @@ const _getOthersBuy = (param) => {
75 goodSkn = result[0].data.order_goods[0].product_skn; 78 goodSkn = result[0].data.order_goods[0].product_skn;
76 } 79 }
77 80
78 - return _getOthersBuy2(Object.assign(param, {skn: goodSkn})); 81 + return _getOthersBuy2(Object.assign(param, { skn: goodSkn }));
79 82
80 }).then((result) => { 83 }).then((result) => {
81 84
@@ -94,25 +97,158 @@ const savePrePayInfo = (params) => { @@ -94,25 +97,158 @@ const savePrePayInfo = (params) => {
94 uid: params.uid, 97 uid: params.uid,
95 orderCode: params.orderCode, 98 orderCode: params.orderCode,
96 payment: params.payment 99 payment: params.payment
97 - }, {code: 200}).then(result => { 100 + }, { code: 200 }).then(result => {
98 return result && result.data; 101 return result && result.data;
99 }); 102 });
100 }; 103 };
101 104
102 /** 105 /**
103 - * 更新订单的支付方式  
104 - * @param params  
105 - * @returns {*|Promise.<TResult>} 106 + * 获取订单支付银行信息
  107 + * @param id
  108 + */
  109 +const getBankByOrder = (id) => {
  110 + return co(function*() {
  111 + let result = yield payApi.getBankByOrder(id);
  112 +
  113 + if (result && result.code === 200 && result.data) {
  114 + return result.data;
  115 + }
  116 + return {};
  117 + })();
  118 +};
  119 +
  120 +/**
  121 + * 设置订单支付银行
  122 + * @param code
  123 + * @param payment
  124 + * @param bankCode
106 */ 125 */
107 -const updateOrderPayment = (params) => { 126 +const setOrderPayBank = (code, payment, bankCode) => {
  127 + return co(function*() {
  128 + let data = yield payApi.setOrderPayBank(code, payment, bankCode);
  129 +
  130 + return data;
  131 + })();
  132 +};
  133 +
  134 +/**
  135 + * 获取支付方式的相关参数, (密钥等信息)
  136 + * @param id
  137 + */
  138 +const getPaymentInfo = (id) => {
  139 + return co(function*() {
  140 + let result = yield payApi.getPaymentInfo(id);
  141 +
  142 + if (result && result.code === 200 && result.data) {
  143 + return result.data;
  144 + }
  145 + return {};
  146 + })();
  147 +};
  148 +
  149 +/**
  150 + * 支付确认
  151 + * @param code
  152 + * @param payment
  153 + * @param uid
  154 + */
  155 +const sendPayConfirm = (code, payment, uid) => {
  156 + return co(function*() {
  157 + let data = yield payApi.sendPayConfirm(code, payment, uid);
  158 +
  159 + return data;
  160 + })();
  161 +};
  162 +
  163 +/**
  164 + * 更新订单支付方式
  165 + * @param code
  166 + * @param payment
  167 + * @param uid
  168 + * @returns {*}
  169 + */
  170 +const updateOrderPayment = (code, payment, uid) => {
108 return api.get('', { 171 return api.get('', {
109 method: 'app.SpaceOrders.updateOrdersPaymentByCode', 172 method: 'app.SpaceOrders.updateOrdersPaymentByCode',
110 - order_code: params.orderCode,  
111 - payment: params.payment,  
112 - uid: params.uid  
113 - }, {code: 200}).then(result => {  
114 - return result && result.data; 173 + order_code: code,
  174 + payment: payment,
  175 + uid: uid
  176 + });
  177 +};
  178 +
  179 +/**
  180 + * 更新订单支付银行
  181 + * @param code
  182 + * @param payment
  183 + * @param bankCode
  184 + */
  185 +const updateOrderPayBank = (code, payment, bankCode) => {
  186 + return co(function*() {
  187 + let data = yield payApi.updateOrderPayBank(code, payment, bankCode);
  188 +
  189 + return data;
  190 + })();
  191 +};
  192 +
  193 +/**
  194 + * 支付成功,前端回调时,处理订单信息
  195 + * @param payResult
  196 + * @param uid
  197 + * @param sessionKey
  198 + */
  199 +const procOrderData = (payResult, uid, sessionKey) => {
  200 + return co(function*() {
  201 + let orderCode = payResult.orderCode;
  202 + let result = { code: 400, message: '' };
  203 +
  204 + if (!orderCode) {
  205 + result.message = '未查到订单信息,订单状态更新失败!';
  206 + return result;
  207 + } else {
  208 + let orderInfo = yield _getOtherDetail({
  209 + uid: uid,
  210 + orderCode: orderCode,
  211 + sessionKey: sessionKey
115 }); 212 });
  213 +
  214 + if (orderInfo && orderInfo.data) {
  215 + let order = orderInfo.data;
  216 + let amount = order.payment_amount;
  217 +
  218 + if (order.is_cancel === 'Y') {
  219 + logger.warn('front pay success but order is cancel.', { payResult: payResult, order: order });
  220 +
  221 + payApi.sendMessage(order.mobile, 'error_sms', '支付成功,但订单已取消,订单号为' + orderCode);
  222 + return { code: 417, message: '支付成功,但订单已取消,需联系客服!' };
  223 + }
  224 +
  225 + if (order.payment_status === 'N') {
  226 + logger.warn('front pay success but may be notify fail');
  227 + }
  228 +
  229 + if (_.round(parseFloat(amount), 2) !== _.round(parseFloat(payResult.totalFee), 2)) {
  230 + logger.warn('front pay success but the amount is not same.', { payResult: payResult, order: order });
  231 + return {
  232 + code: 415,
  233 + message: '支付金额与订单金额不一致,订单状态更新失败!'
  234 + };
  235 + }
  236 +
  237 + return {
  238 + code: 200,
  239 + message: '支付成功,请等待发货',
  240 + data: {
  241 + order: order
  242 + }
  243 + };
  244 +
  245 + } else {
  246 + result.message = '未查到订单信息,订单状态更新失败!';
  247 + }
  248 + }
  249 +
  250 + return result;
  251 + })();
116 }; 252 };
117 253
118 /** 254 /**
@@ -125,24 +261,21 @@ const payTool = { @@ -125,24 +261,21 @@ const payTool = {
125 * @returns {[*,*]} 261 * @returns {[*,*]}
126 */ 262 */
127 payAppInfo() { 263 payAppInfo() {
128 - return [  
129 - { 264 + return [{
130 appIcon: '', 265 appIcon: '',
131 payLink: helpers.urlFormat('/shopping/pay/index'), 266 payLink: helpers.urlFormat('/shopping/pay/index'),
132 appId: 'alipay', 267 appId: 'alipay',
133 app: '支付宝支付', 268 app: '支付宝支付',
134 hint: '支付宝钱包支付', 269 hint: '支付宝钱包支付',
135 subHint: '推荐支付宝用户使用' 270 subHint: '推荐支付宝用户使用'
136 - },  
137 - { 271 + }, {
138 appIcon: '', 272 appIcon: '',
139 payLink: '', 273 payLink: '',
140 appId: 'weixin', 274 appId: 'weixin',
141 app: '微信支付', 275 app: '微信支付',
142 hint: '推荐使用', 276 hint: '推荐使用',
143 subHint: '' 277 subHint: ''
144 - }  
145 - ]; 278 + }];
146 }, 279 },
147 280
148 /** 281 /**
@@ -264,6 +397,12 @@ module.exports = { @@ -264,6 +397,12 @@ module.exports = {
264 getOtherDetail: _getOtherDetail, 397 getOtherDetail: _getOtherDetail,
265 savePrePayInfo, 398 savePrePayInfo,
266 updateOrderPayment, 399 updateOrderPayment,
  400 + updateOrderPayBank,
  401 + getBankByOrder,
  402 + getPaymentInfo,
  403 + setOrderPayBank,
  404 + sendPayConfirm,
  405 + procOrderData,
267 payCenter, 406 payCenter,
268 getPayCod, 407 getPayCod,
269 getPayAli 408 getPayAli