Authored by 陈峰

Merge branch 'feature/cart' of http://git.yoho.cn/fe/yohobuywap-node into feature/cart

@@ -120,6 +120,8 @@ nbactions.xml @@ -120,6 +120,8 @@ nbactions.xml
120 # sftp configuration file 120 # sftp configuration file
121 sftp-config.json 121 sftp-config.json
122 122
  123 +### TSD ###
  124 +typings/
123 125
124 ### Vim ### 126 ### Vim ###
125 # swap 127 # swap
@@ -6,6 +6,7 @@ const cartModel = require('../models/cart'); @@ -6,6 +6,7 @@ const cartModel = require('../models/cart');
6 const headerModel = require('../../../doraemon/models/header'); 6 const headerModel = require('../../../doraemon/models/header');
7 const userModel = require('../../serverAPI/user'); 7 const userModel = require('../../serverAPI/user');
8 const addressModel = require('../../serverAPI/user/address'); 8 const addressModel = require('../../serverAPI/user/address');
  9 +const orderModel = require('../models/order');
9 10
10 11
11 exports.orderEnsure = (req, res, next) => { 12 exports.orderEnsure = (req, res, next) => {
@@ -45,9 +46,7 @@ exports.orderEnsure = (req, res, next) => { @@ -45,9 +46,7 @@ exports.orderEnsure = (req, res, next) => {
45 let userProfile = userModel.queryProfile(uid); 46 let userProfile = userModel.queryProfile(uid);
46 let address = addressModel.addressData(uid); 47 let address = addressModel.addressData(uid);
47 48
48 - return Promise.all([order, userProfile, address])  
49 - .then(  
50 - result => { 49 + return Promise.all([order, userProfile, address]).then(result => {
51 order = result[0]; 50 order = result[0];
52 userProfile = result[1]; 51 userProfile = result[1];
53 address = result[2]; 52 address = result[2];
@@ -86,10 +85,7 @@ exports.orderEnsure = (req, res, next) => { @@ -86,10 +85,7 @@ exports.orderEnsure = (req, res, next) => {
86 viewData.title = '确认订单'; 85 viewData.title = '确认订单';
87 86
88 res.render('order-ensure', viewData); 87 res.render('order-ensure', viewData);
89 - }  
90 - )  
91 - .catch(next);  
92 - 88 + }).catch(next);
93 }; 89 };
94 90
95 /** 91 /**
@@ -149,11 +145,13 @@ exports.couponSearch = (req, res, next) => { @@ -149,11 +145,13 @@ exports.couponSearch = (req, res, next) => {
149 })(); 145 })();
150 }; 146 };
151 147
  148 +/**
  149 + * 选择地址
  150 + */
152 exports.selectAddress = (req, res, next) => { 151 exports.selectAddress = (req, res, next) => {
153 let uid = req.user.uid; 152 let uid = req.user.uid;
154 153
155 - return addressModel.addressData(uid)  
156 - .then(address => { 154 + return addressModel.addressData(uid).then(address => {
157 let moreUrl = req.get('Referer') || '/cart/index/new/orderEnsure'; // 取跳过来的url 155 let moreUrl = req.get('Referer') || '/cart/index/new/orderEnsure'; // 取跳过来的url
158 156
159 address = address.data; 157 address = address.data;
@@ -182,7 +180,7 @@ exports.selectAddress = (req, res, next) => { @@ -182,7 +180,7 @@ exports.selectAddress = (req, res, next) => {
182 moreUrl, 180 moreUrl,
183 address 181 address
184 }); 182 });
185 - }); 183 + }).catch(next);
186 }; 184 };
187 185
188 /** 186 /**
@@ -190,14 +188,23 @@ exports.selectAddress = (req, res, next) => { @@ -190,14 +188,23 @@ exports.selectAddress = (req, res, next) => {
190 */ 188 */
191 exports.invoiceInfo = (req, res, next) => { 189 exports.invoiceInfo = (req, res, next) => {
192 let uid = req.user.uid; 190 let uid = req.user.uid;
  191 + let cookieData = req.cookies['order-info'];
  192 + let orderInfo = JSON.parse(cookieData);
193 193
194 - let orderInfo = req.cookies.orderInfo;  
195 -  
196 - try {  
197 - orderInfo = JSON.parse(orderInfo);  
198 - } catch (e) {  
199 - orderInfo = {};  
200 - }  
201 - 194 + co(function* () {
  195 + let userData = yield userModel.queryProfile(uid);
  196 + let mobile = _.get(userData, 'data.mobile', '');
  197 + let addresslist = yield userModel.addressTextData(uid);
  198 + let returnData = orderModel.processInvoiceData(orderInfo, mobile, addresslist);
  199 + let headerData = headerModel.setNav({
  200 + navTitle: '发票信息',
  201 + navBtn: false
  202 + });
202 203
  204 + res.render('select-invoice', _.assign(returnData, {
  205 + pageHeader: headerData,
  206 + module: 'cart',
  207 + page: 'select-invoice'
  208 + })).catch(next);
  209 + })();
203 }; 210 };
1 /** 1 /**
2 - * 支付成功页 2 + * 支付
3 * @author: jing.li<jing.li@yoho.cn> 3 * @author: jing.li<jing.li@yoho.cn>
4 * @date: 2016/10/25 4 * @date: 2016/10/25
5 */ 5 */
@@ -9,6 +9,9 @@ @@ -9,6 +9,9 @@
9 const mRoot = '../models'; 9 const mRoot = '../models';
10 const payModel = require(`${mRoot}/pay`); 10 const payModel = require(`${mRoot}/pay`);
11 const headerModel = require('../../../doraemon/models/header'); // 头部model 11 const headerModel = require('../../../doraemon/models/header'); // 头部model
  12 +const co = require('bluebird').coroutine;
  13 +const helpers = global.yoho.helpers;
  14 +const Payment = require('../helpers/payment');
12 15
13 /** 16 /**
14 * 支付中心 17 * 支付中心
@@ -17,6 +20,18 @@ const headerModel = require('../../../doraemon/models/header'); // 头部model @@ -17,6 +20,18 @@ const headerModel = require('../../../doraemon/models/header'); // 头部model
17 * @param next 20 * @param next
18 */ 21 */
19 const payCenter = (req, res, next) => { 22 const payCenter = (req, res, next) => {
  23 + let orderCode = req.query.order_code;
  24 + let uid = req.user.uid;
  25 + let sessionKey = req.session.TOKEN;
  26 +
  27 + if (!orderCode || !uid) {
  28 + res.redirect('/');
  29 + }
  30 +
  31 + if (sessionKey) {
  32 + sessionKey = sessionKey.substr(0, sessionKey.length - 8);
  33 + }
  34 +
20 let headerData = headerModel.setNav({ 35 let headerData = headerModel.setNav({
21 navTitle: '支付中心' 36 navTitle: '支付中心'
22 }); 37 });
@@ -29,16 +44,67 @@ const payCenter = (req, res, next) => { @@ -29,16 +44,67 @@ const payCenter = (req, res, next) => {
29 }; 44 };
30 45
31 payModel.payCenter({ 46 payModel.payCenter({
32 - orderCode: req.query.order_code 47 + orderCode: orderCode,
  48 + uid: uid,
  49 + sessionKey: sessionKey
33 }).then(result => { 50 }).then(result => {
34 - res.render('pay/pay-center', Object.assign(responseData, {  
35 - payAppInfo: result.payList 51 + res.render('pay/pay-center', Object.assign(responseData, result, {
  52 + isOldUser: Boolean(req.cookies._isOldUser && req.cookies._isOldUser === '4'),
36 })); 53 }));
37 }).catch(next); 54 }).catch(next);
38 55
39 56
40 }; 57 };
41 58
  59 +/**
  60 + * 支付宝跳转页
  61 + * @param req
  62 + * @param res
  63 + */
  64 +const goAlipay = (req, res, next) => {
  65 + let orderCode = req.query.order_code;
  66 + let user = req.user;
  67 + let uid = req.user.uid;
  68 + let sessionKey = req.session.TOKEN;
  69 + let payment = req.query.payment;
  70 +
  71 + if (!orderCode || !uid || !sessionKey) {
  72 + res.redirect('/');
  73 + }
  74 +
  75 + co(function*() {
  76 + let orderDetail = yield payModel.getOtherDetail({
  77 + uid: uid,
  78 + orderCode: orderCode,
  79 + sessionKey: sessionKey
  80 + });
  81 +
  82 + if (!orderDetail || !orderDetail.data) {
  83 + return res.json({
  84 + code: 400,
  85 + msg: '没有找到该订单!'
  86 + });
  87 + }
  88 +
  89 + if (orderDetail.data.is_cancel === 'Y') {
  90 + let url = helpers.urlFormat('/home/orders/detail', { order_code: orderCode });
  91 +
  92 + return res.json({
  93 + code: 400,
  94 + msg: '订单已经取消'
  95 + }).redirect(url);
  96 + }
  97 +
  98 + Payment.pay(user, orderDetail.data, payment, req.protocol).then(result => {
  99 + if (result && result.data && result.data.href) {
  100 + res.redirect(result.data.href);
  101 + } else {
  102 + res.redirect('/');
  103 + }
  104 + }).catch(next);
  105 + })();
  106 +};
  107 +
42 // 货到付款 108 // 货到付款
43 const payCod = (req, res, next) => { 109 const payCod = (req, res, next) => {
44 let headerData = headerModel.setNav({ 110 let headerData = headerModel.setNav({
@@ -52,12 +118,16 @@ const payCod = (req, res, next) => { @@ -52,12 +118,16 @@ const payCod = (req, res, next) => {
52 title: '支付中心 | Yoho!Buy有货 | 潮流购物逛不停' 118 title: '支付中心 | Yoho!Buy有货 | 潮流购物逛不停'
53 }; 119 };
54 120
  121 + let sessionKey = req.session.TOKEN;
  122 +
  123 +
55 let param = { 124 let param = {
56 uid: req.user.uid, 125 uid: req.user.uid,
57 udid: req.sessionID || require('md5')(req.ip) || 'yoho', 126 udid: req.sessionID || require('md5')(req.ip) || 'yoho',
58 orderCode: req.query.order_code, 127 orderCode: req.query.order_code,
59 contentCode: '05afedf76886d732573f10f7451a1703', 128 contentCode: '05afedf76886d732573f10f7451a1703',
60 - client_id: req.cookies._yasvd || '' 129 + client_id: req.cookies._yasvd || '',
  130 + sessionKey: sessionKey && sessionKey.substr(0, sessionKey.length - 8) || ''
61 }; 131 };
62 132
63 // 如果没有uid,跳转到首页 133 // 如果没有uid,跳转到首页
@@ -76,7 +146,7 @@ const payCod = (req, res, next) => { @@ -76,7 +146,7 @@ const payCod = (req, res, next) => {
76 }).catch(next); 146 }).catch(next);
77 }; 147 };
78 148
79 -// 支付宝支付 149 +// 支付宝支付结果页
80 const payAli = (req, res, next) => { 150 const payAli = (req, res, next) => {
81 let headerData = headerModel.setNav({ 151 let headerData = headerModel.setNav({
82 navTitle: '支付完成' 152 navTitle: '支付完成'
@@ -114,6 +184,7 @@ const payAli = (req, res, next) => { @@ -114,6 +184,7 @@ const payAli = (req, res, next) => {
114 184
115 module.exports = { 185 module.exports = {
116 payCenter, 186 payCenter,
  187 + goAlipay,
117 payCod, 188 payCod,
118 payAli 189 payAli
119 }; 190 };
  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 + *
  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 sign = require('./sign');
  12 +const md5 = require('md5');
  13 +const logger = global.yoho.logger;
  14 +const AlipayConfig = config.alipayConfig;
  15 +
  16 +const Alipay = {
  17 +
  18 + pay(user, order, param, protocol) {
  19 + let params = {
  20 + service: AlipayConfig.service,
  21 + partner: AlipayConfig.partner,
  22 + _input_charset: AlipayConfig.inputCharset,
  23 + notify_url: config.domains.service + 'payment/alipay_notify',
  24 + return_url: protocol + ':' + helpers.urlFormat(AlipayConfig.returnUrl),
  25 + subject: '有货订单号:' + order.order_code,
  26 + out_trade_no: order.order_code,
  27 + it_b_pay: order.pay_expire,
  28 + total_fee: parseFloat(order.payment_amount),
  29 + seller_id: AlipayConfig.partner,
  30 + payment_type: '1',
  31 + show_url: protocol + ':' + helpers.urlFormat('/home/orderdetail', { order_code: order.order_code })
  32 + };
  33 +
  34 + // TODO 防钓鱼配置,参考php
  35 +
  36 + let signStr = md5(sign.raw(params) + AlipayConfig.alipayKey);
  37 + let body = sign.rawUncode(params) + '&sign=' + signStr + '&sign_type=MD5';
  38 +
  39 + return {
  40 + code: 200,
  41 + data: {
  42 + href: AlipayConfig.payUrl + '?' + body
  43 + }
  44 + };
  45 + },
  46 + notify(data, param) {
  47 + let payParams = JSON.parse(param.payParams);
  48 +
  49 + logger.info(`Alipay notify, params = ${JSON.stringify(data)}`);
  50 +
  51 + if (!this.checkNotify(data, payParams)) {
  52 + return { payResult: -1 };
  53 + } else {
  54 + let orderCode = parseInt(data.out_trade_no, 10);
  55 +
  56 + return {
  57 + bankName: '',
  58 + orderCode: orderCode,
  59 + payResult: data.trade_status === 'TRADE_SUCCESS' ? 200 : 400,
  60 + payTime: data.gmt_payment || '',
  61 + totalFee: data.total_fee,
  62 + resultMsg: data.notify_type,
  63 + payOrderCode: orderCode,
  64 + tradeNo: data.trade_no,
  65 + bankBillNo: ''
  66 + };
  67 + }
  68 + },
  69 +
  70 + checkNotify(data, payParams) {
  71 + let signValue = data.sign;
  72 +
  73 + delete data.sign;
  74 + delete data.sign_type;
  75 + delete data.code;
  76 +
  77 + let signStr = md5(sign.raw(data) + payParams.merchant_key);
  78 +
  79 + return signValue === signStr;
  80 + }
  81 +};
  82 +
  83 +module.exports = Alipay;
  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 +/**
  2 + *
  3 + * @author: jiangfeng<jeff.jiang@yoho.cn>
  4 + * @date: 16/7/22
  5 + */
  6 +'use strict';
  7 +const moment = require('moment');
  8 +const xml2js = require('xml2js');
  9 +
  10 +const common = {
  11 + getPayExpireMin(expire) {
  12 + let defaultValue = 120;
  13 +
  14 + if (expire) {
  15 + let expireTime = moment(expire, 'YYYY-MM-DD HH:mm:ss');
  16 + let diff = expireTime.diff(moment());
  17 +
  18 + return Math.floor(diff / 1000 / 60);
  19 +
  20 + // if (diff > 0) {
  21 + // return Math.floor(diff / 1000 / 60);
  22 + // } else {
  23 + // return 0;
  24 + // }
  25 +
  26 + } else {
  27 + return defaultValue;
  28 + }
  29 + },
  30 + getPayExpireCouple(expire) {
  31 + let start = expire ? moment(expire, 'YYYY-MM-DD HH:mm:ss') : moment();
  32 + let end = expire ? moment(expire, 'YYYY-MM-DD HH:mm:ss') : moment();
  33 +
  34 + return {
  35 + start: start.subtract(2, 'hours'),
  36 + end: end.add(5, 'minutes')
  37 + };
  38 + },
  39 + nonceStr(length) {
  40 + length = length || 32;
  41 +
  42 + let chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
  43 + let str = '';
  44 +
  45 + for (let i = 0; i < length; i++) {
  46 + str += chars[parseInt(Math.random() * length, 10)];
  47 + }
  48 + return str;
  49 + },
  50 + toXml(obj, root) {
  51 + let xmlBuilder = new xml2js.Builder({
  52 + rootName: root || 'xml'
  53 + });
  54 +
  55 + return xmlBuilder.buildObject(obj);
  56 + },
  57 + xml2Obj(xml) {
  58 + let xmlParser = new xml2js.Parser({
  59 + trim: true,
  60 + explicitArray: false
  61 + });
  62 +
  63 + return new Promise((resolve, reject) => {
  64 + xmlParser.parseString(xml, (err, result) => {
  65 + if (err) {
  66 + reject(err);
  67 + } else {
  68 + resolve(result);
  69 + }
  70 + });
  71 + });
  72 + }
  73 +};
  74 +
  75 +module.exports = common;
  1 +/**
  2 + *
  3 + * @author: jiangfeng<jeff.jiang@yoho.cn>
  4 + * @date: 16/7/22
  5 + */
  6 +'use strict';
  7 +
  8 +const Sign = {
  9 + raw(args) {
  10 + let keys = Object.keys(args);
  11 +
  12 + keys = keys.filter(k => {
  13 + return args[k] === '' || args[k] === 'undefined' ? false : true;
  14 + }).sort();
  15 +
  16 + return keys.map(k => {
  17 + return k + '=' + decodeURI(args[k]);
  18 + }).join('&');
  19 + },
  20 +
  21 + rawUncode(args) {
  22 + let keys = Object.keys(args);
  23 +
  24 + keys = keys.filter(k => {
  25 + return args[k] === '' || args[k] === 'undefined' ? false : true;
  26 + }).sort();
  27 +
  28 + return keys.map(k => {
  29 + return k.toLowerCase() + '=' + args[k];
  30 + }).join('&');
  31 + }
  32 +};
  33 +
  34 +module.exports = Sign;
  1 +/**
  2 + *
  3 + * @author: jiangfeng<jeff.jiang@yoho.cn>
  4 + * @date: 16/9/8
  5 + */
  6 +'use strict';
  7 +
  8 +const ServiceAPI = global.yoho.ServiceAPI;
  9 +const helpers = global.yoho.helpers;
  10 +
  11 +const Wechat = {
  12 + pay(user, order, info) {
  13 + return ServiceAPI.get('payment/weixin_data', {
  14 + order_code: order.order_code,
  15 + payment_code: info.id,
  16 + app_key: 'blkpc'
  17 + }).then(result => {
  18 + if (result && result.code === 200 && result.data) {
  19 + let url = `/shopping/pay/online/weixin?url=${result.data.codeUrl}&code=${order.order_code}`;
  20 +
  21 + return {
  22 + code: 200,
  23 + data: {
  24 + href: helpers.urlFormat(url)
  25 + }
  26 + };
  27 + } else {
  28 + return {
  29 + code: 400,
  30 + message: result.message
  31 + };
  32 + }
  33 + });
  34 + }
  35 +};
  36 +
  37 +module.exports = Wechat;
  1 +/**
  2 + * 各种支付的入口
  3 + * TAR NOTE: 本项目中仅支持支付宝和微信支付,其他支付方式需调试
  4 + * @author: jiangfeng<jeff.jiang@yoho.cn>
  5 + * @date: 16/7/22
  6 + */
  7 +
  8 +'use strict';
  9 +
  10 +const PayModel = require('../models/pay');
  11 +const Alipay = require('./pay/alipay');
  12 +const Alibank = require('./pay/alibank');
  13 +const Wechat = require('./pay/wechat');
  14 +const Promise = require('bluebird');
  15 +const co = Promise.coroutine;
  16 +const logger = global.yoho.logger;
  17 +
  18 +const Payment = {
  19 + pay(user, order, payType, protocol) {
  20 + return co(function*() {
  21 + let result = {
  22 + code: 400,
  23 + message: '获取支付方式信息失败'
  24 + };
  25 + let paymentPars = payType.split('_');
  26 + let payInfo;
  27 + let bankCode = '';
  28 +
  29 + if (paymentPars.length !== 2) {
  30 + return result;
  31 + }
  32 +
  33 + if (!order.order_code) {
  34 + result.message = '没有找到该订单';
  35 + return result;
  36 + }
  37 +
  38 + if (order.is_cancel && order.is_cancel === 'Y') {
  39 + result.message = '该订单已经取消';
  40 + return result;
  41 + }
  42 +
  43 + // if (order.pay_expire && common.getPayExpireMin(order.pay_expire) <= 0) {
  44 + // result.message = '当前订单不可支付'; // 该订单已超过2个小时
  45 + // return result;
  46 + // }
  47 +
  48 + let method = paymentPars[0] * 1;
  49 +
  50 + if (method === PayModel.payments.wechat) {
  51 + // 如果是微信支付,不需要调用获取支付方式详情接口
  52 + result = yield Wechat.pay(user, order, { id: PayModel.payments.wechat });
  53 + } else {
  54 + payInfo = yield PayModel.getPaymentInfo(method);
  55 +
  56 + if (!payInfo.payParams) {
  57 + return result;
  58 + }
  59 +
  60 + switch (payInfo.id) {
  61 + case PayModel.payments.alipay:
  62 + result = Alipay.pay(user, order, payInfo, protocol);
  63 + break;
  64 + case PayModel.payments.alibank:
  65 + bankCode = paymentPars[1];
  66 + payInfo.bankCode = bankCode; // 设置默认银行
  67 + result = Alibank.pay(user, order, payInfo, protocol);
  68 + break;
  69 + default:
  70 + break;
  71 + }
  72 + }
  73 +
  74 + logger.info(`pay to url, params = ${JSON.stringify(result)}`);
  75 +
  76 + if (result.code === 200) {
  77 + let updateInfo = yield Payment.beforePay(user, order, method, bankCode);
  78 +
  79 + if (updateInfo && updateInfo.code !== 200) {
  80 + return updateInfo;
  81 + }
  82 + }
  83 +
  84 + return result;
  85 + })();
  86 + },
  87 +
  88 + beforePay(user, order, method, bankCode) {
  89 + return Promise.all([
  90 + PayModel.updateOrderPayment(order.order_code, method, user.uid),
  91 + PayModel.getBankByOrder(order.order_code)
  92 + ]).then(result => {
  93 + let paymentRecord = result[0];
  94 + let bankRecord = result[1];
  95 +
  96 + if (!paymentRecord || paymentRecord.code !== 200) {
  97 + let message = paymentRecord && paymentRecord.message ? paymentRecord.message : '系统繁忙,请稍后再试';
  98 +
  99 + return { code: 400, message: message };
  100 + }
  101 +
  102 + if (bankRecord && bankRecord.bankCode) {
  103 + return PayModel.updateOrderPayBank(order.order_code, method, bankCode);
  104 + } else {
  105 + return PayModel.setOrderPayBank(order.order_code, method, bankCode);
  106 + }
  107 +
  108 + }).catch(e => {
  109 + logger.error('update order pay info error.', e);
  110 +
  111 + return Promise.resolve({
  112 + code: 400,
  113 + message: '更新订单支付信息失败'
  114 + });
  115 + });
  116 + },
  117 +
  118 + afterPay(query, payId, user, sessionKey) {
  119 + return co(function*() {
  120 + let payInfo = yield PayModel.getPaymentInfo(payId);
  121 + let payResult = {};
  122 + let payData = {};
  123 + let payName = '';
  124 +
  125 + if (payId === PayModel.payments.alipay) {
  126 + payResult = Alipay.notify(query, payInfo);
  127 + } else if (payId === PayModel.payments.alibank) {
  128 + payResult = Alibank.notify(query, payInfo);
  129 + }
  130 +
  131 + payResult.bankName = payName = payResult.bankName || payInfo.payName || '';
  132 + payResult.bankCode = payResult.bankCode || payInfo.pay_code || '';
  133 +
  134 + // 记录日志
  135 + logger.info(`\r\n\r\n pay back confirmreq = ${JSON.stringify({
  136 + query: query,
  137 + payId: payId,
  138 + user: user,
  139 + payResult: payResult
  140 + })}`);
  141 +
  142 + if (payResult && payResult.payResult === 200) {
  143 + if (payResult.orderCode) {
  144 + logger.info('pay back confirm');
  145 + yield PayModel.sendPayConfirm(payResult.orderCode, payId, user.uid);
  146 + }
  147 +
  148 + payData = yield PayModel.procOrderData(payResult, user.uid, sessionKey);
  149 + } else {
  150 + payData = {
  151 + code: 500,
  152 + message: '支付失败'
  153 + };
  154 + }
  155 +
  156 + payData.payName = payName;
  157 +
  158 + return payData;
  159 + })();
  160 + }
  161 +};
  162 +
  163 +module.exports = Payment;
  1 +'use strict';
  2 +
  3 +const _ = require('lodash');
  4 +const crypto = global.yoho.crypto;
  5 +
  6 +const processInvoiceData = (orderInfo, mobile, addresslist) => {
  7 + let invoices_title = '';
  8 + let invoiceType = '7';
  9 + let invoices_type = '2';
  10 + let invoice_Top = '个人';
  11 +
  12 + // 用户手机号处理
  13 + if (orderInfo.receiverMobile && orderInfo.isModifyTel) {
  14 + mobile = orderInfo.receiverMobile;
  15 + } else {
  16 + _.forEach(addresslist, addressValue => {
  17 + if (addressValue.address_id === crypto.encryption('', orderInfo.addressId)) {
  18 + mobile = addressValue.mobile;
  19 + }
  20 + });
  21 + }
  22 +
  23 + // 发票信息处理
  24 + if (orderInfo.invoiceType && orderInfo.invoiceTitle) {
  25 + invoices_title = orderInfo.invoiceText;
  26 + invoiceType = orderInfo.invoiceType;
  27 + invoices_type = orderInfo.invoicesType * 1;
  28 + invoice_Top = orderInfo.invoiceTitle;
  29 + }
  30 +
  31 + return {
  32 + invoiceNotice: '发票须知',
  33 + phone: mobile ? mobile : '', // TODO 字符串替换 ****
  34 + completeTel: mobile,
  35 + isCompany: invoice_Top !== '单位',
  36 + companyName: invoices_title,
  37 + isPaper: invoices_type === 1,
  38 + invoicesType: [
  39 + {
  40 + id: '2',
  41 + type: '电子发票',
  42 + choosed: !invoices_type || invoices_type === 2,
  43 + },
  44 + {
  45 + id: '1',
  46 + type: '纸质发票',
  47 + choosed: invoices_type === 1
  48 + }
  49 + ],
  50 + invoiceTitle: [
  51 + {
  52 + type: '个人',
  53 + choosed: invoice_Top === '个人'
  54 + },
  55 + {
  56 + type: '单位',
  57 + choosed: invoice_Top === '单位'
  58 + }
  59 + ],
  60 + content: [
  61 + {
  62 + choosed: !invoiceType || invoiceType === 7,
  63 + id: 7,
  64 + text: '服装'
  65 + },
  66 + {
  67 + choosed: invoiceType === 9,
  68 + id: 9,
  69 + text: '配件'
  70 + },
  71 + {
  72 + choosed: invoiceType === 11,
  73 + id: 11,
  74 + text: '日用品'
  75 + },
  76 + {
  77 + choosed: invoiceType === 3,
  78 + id: 3,
  79 + text: '办公用品'
  80 + },
  81 + {
  82 + choosed: invoiceType === 6,
  83 + id: 6,
  84 + text: '体育用品'
  85 + },
  86 + {
  87 + choosed: invoiceType === 10,
  88 + id: 10,
  89 + text: '数码产品'
  90 + },
  91 + ]
  92 + };
  93 +
  94 +};
  95 +
  96 +module.exports = {
  97 + processInvoiceData
  98 +};
  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 +};
1 /** 1 /**
2 - * 支付成功页 2 + * 支付
3 * @author: jing.li<jing.li@yoho.cn> 3 * @author: jing.li<jing.li@yoho.cn>
4 * @date: 2016/10/25 4 * @date: 2016/10/25
5 */ 5 */
@@ -10,7 +10,18 @@ const api = global.yoho.API; @@ -10,7 +10,18 @@ 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;
  15 +const _ = require('lodash');
  16 +const co = require('bluebird').coroutine;
  17 +const logger = global.yoho.logger;
  18 +
  19 +// 支付方式
  20 +const payments = {
  21 + alipay: 33,
  22 + wechat: 36,
  23 + alibank: 42
  24 +};
14 25
15 // 资源位 26 // 资源位
16 const _getBanner = (param) => { 27 const _getBanner = (param) => {
@@ -51,7 +62,8 @@ const _getOtherDetail = (param) => { @@ -51,7 +62,8 @@ const _getOtherDetail = (param) => {
51 return api.get('', { 62 return api.get('', {
52 method: 'app.SpaceOrders.detail', 63 method: 'app.SpaceOrders.detail',
53 uid: param.uid, 64 uid: param.uid,
54 - order_code: param.orderCode 65 + order_code: param.orderCode,
  66 + session_key: param.sessionKey
55 }, { 67 }, {
56 code: 200 68 code: 200
57 }).then((result) => { 69 }).then((result) => {
@@ -73,7 +85,7 @@ const _getOthersBuy = (param) => { @@ -73,7 +85,7 @@ const _getOthersBuy = (param) => {
73 goodSkn = result[0].data.order_goods[0].product_skn; 85 goodSkn = result[0].data.order_goods[0].product_skn;
74 } 86 }
75 87
76 - return _getOthersBuy2(Object.assign(param, {skn: goodSkn})); 88 + return _getOthersBuy2(Object.assign(param, { skn: goodSkn }));
77 89
78 }).then((result) => { 90 }).then((result) => {
79 91
@@ -82,29 +94,224 @@ const _getOthersBuy = (param) => { @@ -82,29 +94,224 @@ const _getOthersBuy = (param) => {
82 }; 94 };
83 95
84 /** 96 /**
85 - * 支付中心  
86 - * @param params 97 + * 获取订单支付银行信息
  98 + * @param id
87 */ 99 */
88 -const payCenter = (params) => {  
89 - return Promise.resolve({  
90 - payList: [  
91 - { 100 +const getBankByOrder = (id) => {
  101 + return co(function*() {
  102 + let result = yield payApi.getBankByOrder(id);
  103 +
  104 + if (result && result.code === 200 && result.data) {
  105 + return result.data;
  106 + }
  107 + return {};
  108 + })();
  109 +};
  110 +
  111 +/**
  112 + * 设置订单支付银行
  113 + * @param code
  114 + * @param payment
  115 + * @param bankCode
  116 + */
  117 +const setOrderPayBank = (code, payment, bankCode) => {
  118 + return co(function*() {
  119 + let data = yield payApi.setOrderPayBank(code, payment, bankCode);
  120 +
  121 + return data;
  122 + })();
  123 +};
  124 +
  125 +/**
  126 + * 获取支付方式的相关参数, (密钥等信息)
  127 + * @param id
  128 + */
  129 +const getPaymentInfo = (id) => {
  130 + return co(function*() {
  131 + let result = yield payApi.getPaymentInfo(id);
  132 +
  133 + if (result && result.code === 200 && result.data) {
  134 + return result.data;
  135 + }
  136 + return {};
  137 + })();
  138 +};
  139 +
  140 +/**
  141 + * 支付确认
  142 + * @param code
  143 + * @param payment
  144 + * @param uid
  145 + */
  146 +const sendPayConfirm = (code, payment, uid) => {
  147 + return co(function*() {
  148 + let data = yield payApi.sendPayConfirm(code, payment, uid);
  149 +
  150 + return data;
  151 + })();
  152 +};
  153 +
  154 +/**
  155 + * 更新订单支付方式
  156 + * @param code
  157 + * @param payment
  158 + * @param uid
  159 + * @returns {*}
  160 + */
  161 +const updateOrderPayment = (code, payment, uid) => {
  162 + return api.get('', {
  163 + method: 'app.SpaceOrders.updateOrdersPaymentByCode',
  164 + order_code: code,
  165 + payment: payment,
  166 + uid: uid
  167 + });
  168 +};
  169 +
  170 +/**
  171 + * 更新订单支付银行
  172 + * @param code
  173 + * @param payment
  174 + * @param bankCode
  175 + */
  176 +const updateOrderPayBank = (code, payment, bankCode) => {
  177 + return co(function*() {
  178 + let data = yield payApi.updateOrderPayBank(code, payment, bankCode);
  179 +
  180 + return data;
  181 + })();
  182 +};
  183 +
  184 +/**
  185 + * 支付成功,前端回调时,处理订单信息
  186 + * @param payResult
  187 + * @param uid
  188 + * @param sessionKey
  189 + */
  190 +const procOrderData = (payResult, uid, sessionKey) => {
  191 + return co(function*() {
  192 + let orderCode = payResult.orderCode;
  193 + let result = { code: 400, message: '' };
  194 +
  195 + if (!orderCode) {
  196 + result.message = '未查到订单信息,订单状态更新失败!';
  197 + return result;
  198 + } else {
  199 + let orderInfo = yield _getOtherDetail({
  200 + uid: uid,
  201 + orderCode: orderCode,
  202 + sessionKey: sessionKey
  203 + });
  204 +
  205 + if (orderInfo && orderInfo.data) {
  206 + let order = orderInfo.data;
  207 + let amount = order.payment_amount;
  208 +
  209 + if (order.is_cancel === 'Y') {
  210 + logger.warn('front pay success but order is cancel.', { payResult: payResult, order: order });
  211 +
  212 + payApi.sendMessage(order.mobile, 'error_sms', '支付成功,但订单已取消,订单号为' + orderCode);
  213 + return { code: 417, message: '支付成功,但订单已取消,需联系客服!' };
  214 + }
  215 +
  216 + if (order.payment_status === 'N') {
  217 + logger.warn('front pay success but may be notify fail');
  218 + }
  219 +
  220 + if (_.round(parseFloat(amount), 2) !== _.round(parseFloat(payResult.totalFee), 2)) {
  221 + logger.warn('front pay success but the amount is not same.', { payResult: payResult, order: order });
  222 + return {
  223 + code: 415,
  224 + message: '支付金额与订单金额不一致,订单状态更新失败!'
  225 + };
  226 + }
  227 +
  228 + return {
  229 + code: 200,
  230 + message: '支付成功,请等待发货',
  231 + data: {
  232 + order: order
  233 + }
  234 + };
  235 +
  236 + } else {
  237 + result.message = '未查到订单信息,订单状态更新失败!';
  238 + }
  239 + }
  240 +
  241 + return result;
  242 + })();
  243 +};
  244 +
  245 +/**
  246 + * 支付相关的数据处理函数
  247 + */
  248 +const payTool = {
  249 +
  250 + /**
  251 + * 支持的支付方式列表
  252 + * @returns {[*,*]}
  253 + */
  254 + payAppInfo(orderCode) {
  255 + return [{
92 appIcon: '', 256 appIcon: '',
93 - payLink: helpers.urlFormat('/shopping/pay/index'), 257 + payLink: helpers.urlFormat('/cart/index/new/pay/goalipay', {
  258 + payment: payments.alipay + '_platform',
  259 + order_code: orderCode
  260 + }),
94 appId: 'alipay', 261 appId: 'alipay',
95 app: '支付宝支付', 262 app: '支付宝支付',
96 hint: '支付宝钱包支付', 263 hint: '支付宝钱包支付',
97 subHint: '推荐支付宝用户使用' 264 subHint: '推荐支付宝用户使用'
98 - },  
99 - { 265 + }, {
100 appIcon: '', 266 appIcon: '',
101 payLink: '', 267 payLink: '',
102 appId: 'weixin', 268 appId: 'weixin',
103 app: '微信支付', 269 app: '微信支付',
104 hint: '推荐使用', 270 hint: '推荐使用',
105 subHint: '' 271 subHint: ''
  272 + }];
  273 + },
  274 +
  275 + /**
  276 + * 计算购买商品总数量
  277 + * @param goodsArray
  278 + * @returns {number}
  279 + * @private
  280 + */
  281 + calBuyNumCount(goodsArray) {
  282 + let buyNumCount = 0;
  283 +
  284 + if (_.isArray(goodsArray)) {
  285 + _.forEach(goodsArray, value => {
  286 + buyNumCount = value.buy_number ? parseInt(value.buy_number, 10) : 0;
  287 + });
  288 + }
  289 +
  290 + return buyNumCount;
106 } 291 }
107 - ] 292 +};
  293 +
  294 +/**
  295 + * 支付中心
  296 + * @param params
  297 + */
  298 +const payCenter = (params) => {
  299 +
  300 + return _getOtherDetail({
  301 + uid: params.uid,
  302 + orderCode: params.orderCode
  303 + }).then(result => {
  304 + let resultData = _.get(result, 'data', {});
  305 +
  306 + return {
  307 + payAppInfo: payTool.payAppInfo(params.orderCode),
  308 + orderCode: params.orderCode,
  309 + hasWxShare: true,
  310 + orderTotal: resultData.payment_amount || 0,
  311 + orderTotalFormat: parseInt(resultData.payment_amount, 10),
  312 + orderCount: payTool.calBuyNumCount(resultData.order_goods),
  313 + uid: params.uid
  314 + };
108 }); 315 });
109 }; 316 };
110 317
@@ -181,6 +388,15 @@ const getPayAli = (param) => { @@ -181,6 +388,15 @@ const getPayAli = (param) => {
181 }; 388 };
182 389
183 module.exports = { 390 module.exports = {
  391 + payments,
  392 + getOtherDetail: _getOtherDetail,
  393 + updateOrderPayment,
  394 + updateOrderPayBank,
  395 + getBankByOrder,
  396 + getPaymentInfo,
  397 + setOrderPayBank,
  398 + sendPayConfirm,
  399 + procOrderData,
184 payCenter, 400 payCenter,
185 getPayCod, 401 getPayCod,
186 getPayAli 402 getPayAli
@@ -25,8 +25,10 @@ router.post('/index/seckill/submit', seckill.submit); @@ -25,8 +25,10 @@ router.post('/index/seckill/submit', seckill.submit);
25 25
26 router.get('/index/count', countController.cartCount); 26 router.get('/index/count', countController.cartCount);
27 router.get('/paySuccess/payCod', payController.payCod);// 支付成功,货到付款 27 router.get('/paySuccess/payCod', payController.payCod);// 支付成功,货到付款
28 -router.get('/index/new/pay/center', payController.payCenter);// 支付成功,支付宝付款  
29 -router.get('/index/new/pay/aliwapreturn', payController.payAli);// 支付成功,支付宝付款 28 +
  29 +router.get('/index/new/pay', authMW, payController.payCenter);// 支付中心
  30 +router.get('/index/new/pay/goalipay', authMW, payController.goAlipay);// 跳支付宝支付
  31 +router.get('/index/new/pay/aliwapreturn', authMW, payController.payAli);// 支付宝付款支付成功
30 32
31 router.get('/index/new/orderEnsure', authMW, order.orderEnsure); // 订单结算 33 router.get('/index/new/orderEnsure', authMW, order.orderEnsure); // 订单结算
32 router.get('/index/new/selectCoupon', authMW, order.selectCoupon); // 选择优惠券 页面 34 router.get('/index/new/selectCoupon', authMW, order.selectCoupon); // 选择优惠券 页面
@@ -132,7 +132,7 @@ @@ -132,7 +132,7 @@
132 <input type="hidden" class="user-mobile" value="{{userMobile}}" /> 132 <input type="hidden" class="user-mobile" value="{{userMobile}}" />
133 <span class="title">发票</span> 133 <span class="title">发票</span>
134 <span class="iconfont checkbox {{#if needInvoice}}icon-cb-radio{{else}}icon-radio{{/if}}"></span> 134 <span class="iconfont checkbox {{#if needInvoice}}icon-cb-radio{{else}}icon-radio{{/if}}"></span>
135 - <a id="invoice" class="invoice-info" href="/cart/index/invoiceInfo"> 135 + <a id="invoice" class="invoice-info" href="/cart/index/new/invoiceInfo">
136 <span class="title">发票信息</span> 136 <span class="title">发票信息</span>
137 <span class="invoice-type"><i class="iconfont">&#xe614;</i></span> 137 <span class="invoice-type"><i class="iconfont">&#xe614;</i></span>
138 </a> 138 </a>
@@ -3,7 +3,6 @@ @@ -3,7 +3,6 @@
3 <input id='ordercode' type="hidden" value="{{orderCode}}"> 3 <input id='ordercode' type="hidden" value="{{orderCode}}">
4 {{/if}} 4 {{/if}}
5 <div class="payapp-list"> 5 <div class="payapp-list">
6 - {{log payAppInfo}}  
7 {{# payAppInfo}} 6 {{# payAppInfo}}
8 {{#if payLink}} 7 {{#if payLink}}
9 <a href="{{payLink}}"> 8 <a href="{{payLink}}">
  1 +<div class="invoice-info-page yoho-page">
  2 + <ul class="invoice-form">
  3 + <li>
  4 + <span class="title">发票类型:</span>
  5 + <div class="invoice-type">
  6 + {{#invoicesType}}
  7 + <span {{#if choosed}}class="on"{{/if}} data-id="{{id}}">{{type}}</span>
  8 + {{/invoicesType}}
  9 + </div>
  10 + </li>
  11 + <li>
  12 + <span class="title">发票抬头:</span>
  13 + <div class="invoice-top">
  14 + {{#invoiceTitle}}
  15 + <span {{#if choosed}}class="on"{{/if}}><i class="iconfont choose {{#if choosed}}icon-cb-radio{{else}}icon-radio{{/if}}"></i>{{type}}</span>
  16 + {{/invoiceTitle}}
  17 + </div>
  18 + </li>
  19 + <li {{#isPaper}}style="display: none;"{{/isPaper}} class="tel-area">
  20 + <span class="title"><i class="txt-point">*</i>发票人手机:</span>
  21 + <span class="phone">
  22 + <input type="hidden" class="copy-tel" value="{{completeTel}}">
  23 + <input type="text" name="tel" data-tel="{{completeTel}}" class="tel {{#phone}}istel{{/phone}}" value="{{phone}}" placeholder="可通过手机号在发票服务平台查询">
  24 + </span>
  25 + </li>
  26 +
  27 + <li class="company-area" {{#isCompany}}style="display: none;"{{/isCompany}}><input type="text" name="company" class="company" value="{{companyName}}" placeholder="填写单位名称" maxlength="30"></li>
  28 + </ul>
  29 +
  30 + <ul class="invoice-cont">
  31 + <li class="cont-title">
  32 + <span>发票内容:</span>
  33 + <span class="choose-cont" data-id=""></span>
  34 + </li>
  35 + {{#each content}}
  36 + <li><span class="iconfont choose {{#if choosed}}icon-cb-radio{{else}}icon-radio{{/if}}" data-id="{{id}}"></span>{{text}}</li>
  37 + {{/each}}
  38 + </ul>
  39 +
  40 + <div class="btn-area"><span class="confirm-btn">确认</span></div>
  41 +
  42 + <div class="invoice-notice">
  43 + <div class="mask-bg"></div>
  44 + <div class="notice-area">
  45 + <div class="notice-cont">
  46 + <h2>发票须知</h2>
  47 + <p>1、发票金额不含优惠券/有货币/红包/优惠码/运费,只包含商品实付金额</p>
  48 + <p>2、电子发票:是税局认可的有效收付款凭证,其法律效力、基本用途及使用规定同纸质发票,如需纸质发票可自行下载打印</p>
  49 + </div>
  50 + <div class="think-ok">我知道了</div>
  51 + </div>
  52 + </div>
  53 +
  54 + <input type="hidden" class="edit-flag" value="false" />
  55 + <input type="hidden" class="address-more" value="{{addressMore}}" />
  56 +</div>
@@ -21,3 +21,10 @@ exports.queryProfile = (uid) => { @@ -21,3 +21,10 @@ exports.queryProfile = (uid) => {
21 21
22 return api.get('', params, options); 22 return api.get('', params, options);
23 }; 23 };
  24 +
  25 +exports.addressTextData = (uid) => {
  26 + return api.get('', {
  27 + method: 'app.address.get',
  28 + uid: uid
  29 + });
  30 +};
@@ -16,21 +16,29 @@ module.exports = { @@ -16,21 +16,29 @@ module.exports = {
16 siteUrl: '//m.yohobuy.com', 16 siteUrl: '//m.yohobuy.com',
17 assetUrl: '//127.0.0.1:5001', 17 assetUrl: '//127.0.0.1:5001',
18 domains: { 18 domains: {
19 - // api: 'http://api-test3.yohops.com:9999/',  
20 - // service: 'http://service-test3.yohops.com:9999/',  
21 - // liveApi: 'http://testapi.live.yohops.com:9999/',  
22 - // singleApi: 'http://api-test3.yohops.com:9999/',  
23 - // imSocket: 'ws://im.yohobuy.com:10240',  
24 - // imCs: 'http://im.yohobuy.com/api',  
25 - // imServer: 'http://im.yohobuy.com/server' 19 + api: 'http://api-test3.yohops.com:9999/',
  20 + service: 'http://service-test3.yohops.com:9999/',
  21 + liveApi: 'http://testapi.live.yohops.com:9999/',
  22 + singleApi: 'http://api-test3.yohops.com:9999/',
  23 + imSocket: 'ws://im.yohobuy.com:10240',
  24 + imCs: 'http://im.yohobuy.com/api',
  25 + imServer: 'http://im.yohobuy.com/server',
26 26
27 - api: 'http://dev-api.yohops.com:9999/',  
28 - service: 'http://service.yoho.cn/',  
29 - liveApi: 'http://api.live.yoho.cn/',  
30 - singleApi: 'http://single.yoho.cn/',  
31 - imSocket: 'ws://imsocket.yohobuy.com:10000',  
32 - imCs: 'http://imhttp.yohobuy.com/api',  
33 - imServer: 'http://imhttp.yohobuy.com/server' 27 + // api: 'http://api.yoho.cn/',
  28 + // service: 'http://service.yoho.cn/',
  29 + // liveApi: 'http://api.live.yoho.cn/',
  30 + // singleApi: 'http://single.yoho.cn/',
  31 + // imSocket: 'ws://imsocket.yohobuy.com:10000',
  32 + // imCs: 'http://imhttp.yohobuy.com/api',
  33 + // imServer: 'http://imhttp.yohobuy.com/server'
  34 +
  35 + // api: 'http://dev-api.yohops.com:9999/',
  36 + // service: 'http://service.yoho.cn/',
  37 + // liveApi: 'http://api.live.yoho.cn/',
  38 + // singleApi: 'http://single.yoho.cn/',
  39 + // imSocket: 'ws://imsocket.yohobuy.com:10000',
  40 + // imCs: 'http://imhttp.yohobuy.com/api',
  41 + // imServer: 'http://imhttp.yohobuy.com/server'
34 }, 42 },
35 subDomains: { 43 subDomains: {
36 host: '.m.yohobuy.com', 44 host: '.m.yohobuy.com',
@@ -86,7 +94,20 @@ module.exports = { @@ -86,7 +94,20 @@ module.exports = {
86 appSecret: 'ce21ae4a3f93852279175a167e54509b' 94 appSecret: 'ce21ae4a3f93852279175a167e54509b'
87 } 95 }
88 }, 96 },
89 - zookeeperServer: '192.168.102.168:2188' 97 + zookeeperServer: '192.168.102.168:2188',
  98 + alipayConfig: {
  99 + payUrl: 'https://mapi.alipay.com/gateway.do',
  100 + service: 'alipay.wap.create.direct.pay.by.user',
  101 + partner: '2088701661478015',
  102 + inputCharset: 'utf-8',
  103 + notifyUrl: 'payment/alipay_notify',
  104 + returnUrl: '/shopping/pay/aliwapreturn',
  105 + signType: 'MD5',
  106 + paymentType: '1',
  107 + alipayKey: 'kcxawi9bb07mzh0aq2wcirsf9znusobw',
  108 + sellerMail: 'zfb@yoho.cn',
  109 + merchantUrl: 'http://m.yohobuy.com/home/orders/detail?order_code='
  110 + }
90 }; 111 };
91 112
92 if (isProduction) { 113 if (isProduction) {
@@ -43,6 +43,7 @@ @@ -43,6 +43,7 @@
43 "request-promise": "^3.0.0", 43 "request-promise": "^3.0.0",
44 "serve-favicon": "^2.3.2", 44 "serve-favicon": "^2.3.2",
45 "uuid": "^2.0.3", 45 "uuid": "^2.0.3",
  46 + "xml2js": "^0.4.17",
46 "yoho-node-lib": "0.2.2", 47 "yoho-node-lib": "0.2.2",
47 "yoho-zookeeper": "^1.0.4" 48 "yoho-zookeeper": "^1.0.4"
48 }, 49 },
  1 +/**
  2 + * 发票信息
  3 + * @author: wsl<shuiling.wang@yoho.cn>
  4 + * @date: 2016/6/14
  5 + */
  6 +
  7 +var $ = require('yoho-jquery'),
  8 + tip = require('../plugin/tip'),
  9 + dialog = require('../plugin/dialog'),
  10 + order = require('./order-info');
  11 +
  12 +var $invoiceNotice = $('.invoice-notice'),
  13 + $companyArea = $('.company-area'),
  14 + $editFlag = $('.edit-flag'),
  15 + $chooseCont = $('.choose-cont'),
  16 + $invoiceType = $('.invoice-type'),
  17 + $tel = $('.tel'),
  18 + $company = $('.company'),
  19 + $telArea = $('.tel-area'),
  20 + orderInfo = order.orderInfo,
  21 + $chooseContLi = $('.invoice-cont').find('.icon-cb-radio').parent(),
  22 + $copyTel = $('.copy-tel'),
  23 + isModifyTel = false;
  24 +
  25 +var myreg = /^(((13[0-9]{1})|(14[0-9]{1})|(15[0-9]{1})|(17[0-9]{1})|(18[0-9]{1}))+\d{8})$/,
  26 + linkUrl = $('.address-more').val() || '/cart/index/orderEnsure?cartType=ordinary';
  27 +
  28 +var C_ID = window._ChannelVary[window.cookie('_Channel')] || 1;
  29 +
  30 +require('../common');
  31 +
  32 +if (window.getUid() !== orderInfo('uid')) {
  33 + order.init();
  34 + window.location.reload();
  35 +}
  36 +
  37 +// 单选效果
  38 +function chooseAction(pDom, dom) {
  39 + if (dom.hasClass('icon-cb-radio')) {
  40 + return;
  41 + } else {
  42 + pDom.find('.choose').removeClass('icon-cb-radio icon-radio').addClass('icon-radio');
  43 + dom.removeClass('icon-radio').addClass('icon-cb-radio');
  44 + dom.parent().addClass('on');
  45 + dom.parent().siblings().removeClass('on');
  46 + $editFlag.val('true');
  47 + }
  48 +}
  49 +
  50 +// 确认表单事件
  51 +function confirmAction() {
  52 + var type = $invoiceType.find('.on').data('id'),
  53 + title = $('.invoice-top').find('.on').text(),
  54 + tel = $tel.attr('data-tel'),
  55 + company = $company.val(),
  56 + cont = $chooseCont.data('id');
  57 +
  58 + if ($editFlag.val() === 'true') {
  59 + if (type === 2 && !myreg.test($tel.attr('data-tel'))) {
  60 + tip.show('请输入正确手机号');
  61 + $tel.focus();
  62 + return false;
  63 + } else if (title === '单位' && company.length === 0) {
  64 + tip.show('请填写发票抬头');
  65 + $company.focus();
  66 + return false;
  67 + } else if (title === '单位' && company.length > 30) {
  68 + tip.show('发票抬头不得超过30个汉字');
  69 + $company.focus();
  70 + return false;
  71 + } else {
  72 + dialog.showDialog({
  73 + dialogText: '确认保存修改内容?',
  74 + hasFooter: {
  75 + leftBtnText: '取消',
  76 + rightBtnText: '确定'
  77 + }
  78 + }, function() {
  79 + orderInfo('invoiceText', (title === '单位' ? company : ''));
  80 + orderInfo('invoiceType', cont);
  81 + orderInfo('receiverMobile', tel);
  82 + orderInfo('invoicesType', type);
  83 + orderInfo('invoiceTitle', title);
  84 +
  85 + if (isModifyTel && $copyTel !== tel) {
  86 + orderInfo('isModifyTel', true);
  87 + } else {
  88 + orderInfo('isModifyTel', false);
  89 + }
  90 +
  91 + dialog.showDialog({
  92 + dialogText: '保存成功',
  93 + autoHide: true,
  94 + fast: true
  95 + });
  96 + window.location.href = linkUrl;
  97 + }, function() {
  98 + window.location.href = linkUrl;
  99 + });
  100 + }
  101 + } else {
  102 + window.location.href = linkUrl;
  103 + }
  104 +}
  105 +
  106 +$chooseCont.html($chooseContLi.text()).attr('data-id', $chooseContLi.find('span').data('id'));
  107 +
  108 +// 发票抬头、发票内容选择
  109 +$('.invoice-top span, .invoice-cont li').not('.invoice-cont .cont-title').on('touchstart', function() {
  110 + chooseAction($(this).parent(), $(this).find('.choose'));
  111 +
  112 + if ($(this).parent().hasClass('invoice-cont')) {
  113 + $chooseCont.html($(this).text()).attr('data-id', $(this).find('span').data('id'));
  114 + }
  115 +
  116 + if ($(this).text() === '单位') {
  117 + $companyArea.slideDown();
  118 + }
  119 +
  120 + if ($(this).text() === '个人') {
  121 + $companyArea.slideUp();
  122 + }
  123 +});
  124 +
  125 +// 发票类型选择
  126 +$('.invoice-type span').on('touchstart', function() {
  127 + if ($(this).hasClass('on')) {
  128 + return;
  129 + } else {
  130 + $(this).addClass('on').siblings().removeClass('on');
  131 + $editFlag.val('true');
  132 +
  133 + // 纸质发票不显示手机号
  134 + if ($(this).index() === 1) {
  135 + $telArea.slideUp();
  136 + } else {
  137 + $telArea.slideDown();
  138 + }
  139 + }
  140 +});
  141 +
  142 +// 发票须知
  143 +$('.invoice-btn').on('touchstart', function() {
  144 + $invoiceNotice.fadeIn();
  145 + return false;
  146 +});
  147 +
  148 +// 关闭发票须知弹框
  149 +$('.think-ok, .mask-bg').on('touchstart', function() {
  150 + $invoiceNotice.fadeOut();
  151 +});
  152 +
  153 +// 电话清空
  154 +$('.istel').one('input', function() {
  155 + $(this).val('').removeClass('istel');
  156 +});
  157 +
  158 +$tel.on('input', function() {
  159 + $(this).attr('data-tel', $(this).val());
  160 + $editFlag.val('true');
  161 + isModifyTel = true;
  162 +});
  163 +
  164 +$company.on('input', function() {
  165 + $editFlag.val('true');
  166 +});
  167 +
  168 +// 确认及返回事件
  169 +$('.confirm-btn, .nav-back').on('touchstart', function(e) {
  170 +
  171 + setTimeout(function() {
  172 + if (window._yas && window._yas.sendCustomInfo) {
  173 + window._yas.sendCustomInfo({
  174 + op: 'YB_SC_INVOICE_INFO_SAVE',
  175 + param: JSON.stringify({
  176 + C_ID: C_ID,
  177 + INVOICE_TYPE: $invoiceType.find('.on').data('id'),
  178 + INVOICE_TITLE: $('.invoice-top').find('.on').text(),
  179 + INVOICE_CONTENT: $chooseCont.data('id')
  180 + })
  181 + }, true);
  182 + }
  183 + }, 200);
  184 +
  185 + e.preventDefault();
  186 + confirmAction();
  187 +});
  188 +
  189 +// initData();
@@ -590,7 +590,7 @@ @@ -590,7 +590,7 @@
590 590
591 span { 591 span {
592 display: inline-block; 592 display: inline-block;
593 - width: 130px; 593 + width: 160px;
594 } 594 }
595 } 595 }
596 596