Authored by 陈峰

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

... ... @@ -120,6 +120,8 @@ nbactions.xml
# sftp configuration file
sftp-config.json
### TSD ###
typings/
### Vim ###
# swap
... ...
... ... @@ -6,6 +6,7 @@ const cartModel = require('../models/cart');
const headerModel = require('../../../doraemon/models/header');
const userModel = require('../../serverAPI/user');
const addressModel = require('../../serverAPI/user/address');
const orderModel = require('../models/order');
exports.orderEnsure = (req, res, next) => {
... ... @@ -45,9 +46,7 @@ exports.orderEnsure = (req, res, next) => {
let userProfile = userModel.queryProfile(uid);
let address = addressModel.addressData(uid);
return Promise.all([order, userProfile, address])
.then(
result => {
return Promise.all([order, userProfile, address]).then(result => {
order = result[0];
userProfile = result[1];
address = result[2];
... ... @@ -86,10 +85,7 @@ exports.orderEnsure = (req, res, next) => {
viewData.title = '确认订单';
res.render('order-ensure', viewData);
}
)
.catch(next);
}).catch(next);
};
/**
... ... @@ -149,11 +145,13 @@ exports.couponSearch = (req, res, next) => {
})();
};
/**
* 选择地址
*/
exports.selectAddress = (req, res, next) => {
let uid = req.user.uid;
return addressModel.addressData(uid)
.then(address => {
return addressModel.addressData(uid).then(address => {
let moreUrl = req.get('Referer') || '/cart/index/new/orderEnsure'; // 取跳过来的url
address = address.data;
... ... @@ -182,7 +180,7 @@ exports.selectAddress = (req, res, next) => {
moreUrl,
address
});
});
}).catch(next);
};
/**
... ... @@ -190,14 +188,23 @@ exports.selectAddress = (req, res, next) => {
*/
exports.invoiceInfo = (req, res, next) => {
let uid = req.user.uid;
let cookieData = req.cookies['order-info'];
let orderInfo = JSON.parse(cookieData);
let orderInfo = req.cookies.orderInfo;
try {
orderInfo = JSON.parse(orderInfo);
} catch (e) {
orderInfo = {};
}
co(function* () {
let userData = yield userModel.queryProfile(uid);
let mobile = _.get(userData, 'data.mobile', '');
let addresslist = yield userModel.addressTextData(uid);
let returnData = orderModel.processInvoiceData(orderInfo, mobile, addresslist);
let headerData = headerModel.setNav({
navTitle: '发票信息',
navBtn: false
});
res.render('select-invoice', _.assign(returnData, {
pageHeader: headerData,
module: 'cart',
page: 'select-invoice'
})).catch(next);
})();
};
... ...
/**
* 支付成功页
* 支付
* @author: jing.li<jing.li@yoho.cn>
* @date: 2016/10/25
*/
... ... @@ -9,6 +9,9 @@
const mRoot = '../models';
const payModel = require(`${mRoot}/pay`);
const headerModel = require('../../../doraemon/models/header'); // 头部model
const co = require('bluebird').coroutine;
const helpers = global.yoho.helpers;
const Payment = require('../helpers/payment');
/**
* 支付中心
... ... @@ -17,6 +20,18 @@ const headerModel = require('../../../doraemon/models/header'); // 头部model
* @param next
*/
const payCenter = (req, res, next) => {
let orderCode = req.query.order_code;
let uid = req.user.uid;
let sessionKey = req.session.TOKEN;
if (!orderCode || !uid) {
res.redirect('/');
}
if (sessionKey) {
sessionKey = sessionKey.substr(0, sessionKey.length - 8);
}
let headerData = headerModel.setNav({
navTitle: '支付中心'
});
... ... @@ -29,16 +44,67 @@ const payCenter = (req, res, next) => {
};
payModel.payCenter({
orderCode: req.query.order_code
orderCode: orderCode,
uid: uid,
sessionKey: sessionKey
}).then(result => {
res.render('pay/pay-center', Object.assign(responseData, {
payAppInfo: result.payList
res.render('pay/pay-center', Object.assign(responseData, result, {
isOldUser: Boolean(req.cookies._isOldUser && req.cookies._isOldUser === '4'),
}));
}).catch(next);
};
/**
* 支付宝跳转页
* @param req
* @param res
*/
const goAlipay = (req, res, next) => {
let orderCode = req.query.order_code;
let user = req.user;
let uid = req.user.uid;
let sessionKey = req.session.TOKEN;
let payment = req.query.payment;
if (!orderCode || !uid || !sessionKey) {
res.redirect('/');
}
co(function*() {
let orderDetail = yield payModel.getOtherDetail({
uid: uid,
orderCode: orderCode,
sessionKey: sessionKey
});
if (!orderDetail || !orderDetail.data) {
return res.json({
code: 400,
msg: '没有找到该订单!'
});
}
if (orderDetail.data.is_cancel === 'Y') {
let url = helpers.urlFormat('/home/orders/detail', { order_code: orderCode });
return res.json({
code: 400,
msg: '订单已经取消'
}).redirect(url);
}
Payment.pay(user, orderDetail.data, payment, req.protocol).then(result => {
if (result && result.data && result.data.href) {
res.redirect(result.data.href);
} else {
res.redirect('/');
}
}).catch(next);
})();
};
// 货到付款
const payCod = (req, res, next) => {
let headerData = headerModel.setNav({
... ... @@ -52,12 +118,16 @@ const payCod = (req, res, next) => {
title: '支付中心 | Yoho!Buy有货 | 潮流购物逛不停'
};
let sessionKey = req.session.TOKEN;
let param = {
uid: req.user.uid,
udid: req.sessionID || require('md5')(req.ip) || 'yoho',
orderCode: req.query.order_code,
contentCode: '05afedf76886d732573f10f7451a1703',
client_id: req.cookies._yasvd || ''
client_id: req.cookies._yasvd || '',
sessionKey: sessionKey && sessionKey.substr(0, sessionKey.length - 8) || ''
};
// 如果没有uid,跳转到首页
... ... @@ -76,7 +146,7 @@ const payCod = (req, res, next) => {
}).catch(next);
};
// 支付宝支付
// 支付宝支付结果页
const payAli = (req, res, next) => {
let headerData = headerModel.setNav({
navTitle: '支付完成'
... ... @@ -114,6 +184,7 @@ const payAli = (req, res, next) => {
module.exports = {
payCenter,
goAlipay,
payCod,
payAli
};
... ...
/**
* TAR NOTE: 从 YOHO-BLK 项目复制,未针对本项目做适配
* @author: jiangfeng<jeff.jiang@yoho.cn>
* @date: 16/7/22
*/
'use strict';
const config = global.yoho.config;
const helpers = global.yoho.helpers;
const common = require('./common');
const sign = require('./sign');
const payHelpersBank = require('./bank');
const md5 = require('md5');
const logger = global.yoho.logger;
const ALIPAY_URL = 'https://mapi.alipay.com/gateway.do';
const Alibank = {
pay(user, order, param, protocol) {
let payParams = JSON.parse(param.payParams);
let extraParam = JSON.stringify({
sign_id_ext: user.uid,
defaultbank: param.bankCode || ''
});
let params = {
service: 'create_direct_pay_by_user',
partner: payParams.merchant_id,
_input_charset: 'utf-8',
notify_url: config.pay.serviceNotify + 'payment/alipay_notify',
return_url: protocol + ':' + helpers.urlFormat('/shopping/pay/callback/alibank'),
subject: 'BLK订单号:' + order.order_code,
out_trade_no: order.order_code,
it_b_pay: common.getPayExpireMin(order.pay_expire) + 'm',
total_fee: order.payment_amount,
payment_type: '1',
defaultbank: param.bankCode,
seller_email: payParams.merchant_other_code,
extra_common_param: extraParam
};
// TODO 防钓鱼配置,参考php
let signStr = md5(sign.raw(params) + payParams.merchant_key);
let body = sign.rawUncode(params) + '&sign=' + signStr + '&sign_type=MD5';
return {
code: 200,
data: {
href: ALIPAY_URL + '?' + body
}
};
},
notify(data, param) {
let payParams = param.payParams && JSON.parse(param.payParams) || {};
let orderCode = parseInt(data.out_trade_no, 10);
let extraParam = data.extra_common_param && JSON.parse(data.extra_common_param) || {};
let bankName = payHelpersBank.getList()[extraParam.defaultbank] &&
payHelpersBank.getList()[extraParam.defaultbank].name || '';
logger.info(`Alibank notify, params = ${JSON.stringify(data)}`);
if (!this.checkNotify(data, payParams)) {
return {payResult: -1, bankName: bankName};
} else {
return {
bankName: bankName,
orderCode: orderCode,
payResult: data.trade_status === 'TRADE_SUCCESS' ? 200 : 400,
payTime: data.gmt_payment || '',
totalFee: data.total_fee,
resultMsg: data.notify_type,
payOrderCode: orderCode,
tradeNo: data.trade_no,
bankBillNo: data.bank_seq_no || ''
};
}
},
checkNotify(data, payParams) {
let signValue = data.sign;
if (!payParams || !data) {
return false;
}
delete data.sign;
delete data.sign_type;
delete data.code;
let signStr = md5(sign.raw(data) + payParams.merchant_key);
return signValue === signStr;
}
};
module.exports = Alibank;
... ...
/**
*
* @author: jiangfeng<jeff.jiang@yoho.cn>
* @date: 16/7/22
*/
'use strict';
const config = global.yoho.config;
const helpers = global.yoho.helpers;
const sign = require('./sign');
const md5 = require('md5');
const logger = global.yoho.logger;
const AlipayConfig = config.alipayConfig;
const Alipay = {
pay(user, order, param, protocol) {
let params = {
service: AlipayConfig.service,
partner: AlipayConfig.partner,
_input_charset: AlipayConfig.inputCharset,
notify_url: config.domains.service + 'payment/alipay_notify',
return_url: protocol + ':' + helpers.urlFormat(AlipayConfig.returnUrl),
subject: '有货订单号:' + order.order_code,
out_trade_no: order.order_code,
it_b_pay: order.pay_expire,
total_fee: parseFloat(order.payment_amount),
seller_id: AlipayConfig.partner,
payment_type: '1',
show_url: protocol + ':' + helpers.urlFormat('/home/orderdetail', { order_code: order.order_code })
};
// TODO 防钓鱼配置,参考php
let signStr = md5(sign.raw(params) + AlipayConfig.alipayKey);
let body = sign.rawUncode(params) + '&sign=' + signStr + '&sign_type=MD5';
return {
code: 200,
data: {
href: AlipayConfig.payUrl + '?' + body
}
};
},
notify(data, param) {
let payParams = JSON.parse(param.payParams);
logger.info(`Alipay notify, params = ${JSON.stringify(data)}`);
if (!this.checkNotify(data, payParams)) {
return { payResult: -1 };
} else {
let orderCode = parseInt(data.out_trade_no, 10);
return {
bankName: '',
orderCode: orderCode,
payResult: data.trade_status === 'TRADE_SUCCESS' ? 200 : 400,
payTime: data.gmt_payment || '',
totalFee: data.total_fee,
resultMsg: data.notify_type,
payOrderCode: orderCode,
tradeNo: data.trade_no,
bankBillNo: ''
};
}
},
checkNotify(data, payParams) {
let signValue = data.sign;
delete data.sign;
delete data.sign_type;
delete data.code;
let signStr = md5(sign.raw(data) + payParams.merchant_key);
return signValue === signStr;
}
};
module.exports = Alipay;
... ...
/**
* Created by TaoHuang on 2016/7/18.
*/
'use strict';
const Bank = {
getList() {
return {
BOCB2C: {
name: '中国银行',
ico: '//static.yohobuy.com/images/pay/icon/zhongguo.png'
},
ABC: {
name: '中国农业银行',
ico: '//static.yohobuy.com/images/pay/icon/nongye.png'
},
SPABANK: {
name: '平安银行',
ico: '//static.yohobuy.com/images/pay/icon/pingan.png'
},
CMBC: {
name: '中国民生银行',
ico: '//static.yohobuy.com/images/pay/icon/minsheng.png'
},
ICBCB2C: {
name: '中国工商银行',
ico: '//static.yohobuy.com/images/pay/icon/gongshang.png'
},
SPDB: {
name: '浦发银行',
ico: '//static.yohobuy.com/images/pay/icon/pufa.png'
},
BJRCB: {
name: '北京农商银行',
ico: '//static.yohobuy.com/images/pay/icon/beijingnongshang.png'
},
HZCBB2C: {
name: '杭州银行',
ico: '//static.yohobuy.com/images/pay/icon/hangzhou.png'
},
CMB: {
name: '招商银行',
ico: '//static.yohobuy.com/images/pay/icon/zhaoshang.png'
},
CIB: {
name: '兴业银行',
ico: '//static.yohobuy.com/images/pay/icon/xingye.png'
},
FDB: {
name: '富滇银行',
ico: '//static.yohobuy.com/images/pay/icon/fudian.png'
},
CEBDEBIT: {
name: '中国光大银行',
ico: '//static.yohobuy.com/images/pay/icon/guangda.png'
},
CCB: {
name: '中国建设银行',
ico: '//static.yohobuy.com/images/pay/icon/zhongguojianshe.png'
},
GDB: {
name: '广发银行',
ico: '//static.yohobuy.com/images/pay/icon/guangfa.png'
},
POSTGC: {
name: '中国邮政储蓄',
ico: '//static.yohobuy.com/images/pay/icon/zhongguoyouzhengchuxu.png'
},
SHBANK: {
name: '上海银行',
ico: '//static.yohobuy.com/images/pay/icon/shanghai.png'
},
NBBANK: {
name: '宁波银行',
ico: '//static.yohobuy.com/images/pay/icon/ningbo.png'
}
};
}
};
module.exports = Bank;
... ...
/**
*
* @author: jiangfeng<jeff.jiang@yoho.cn>
* @date: 16/7/22
*/
'use strict';
const moment = require('moment');
const xml2js = require('xml2js');
const common = {
getPayExpireMin(expire) {
let defaultValue = 120;
if (expire) {
let expireTime = moment(expire, 'YYYY-MM-DD HH:mm:ss');
let diff = expireTime.diff(moment());
return Math.floor(diff / 1000 / 60);
// if (diff > 0) {
// return Math.floor(diff / 1000 / 60);
// } else {
// return 0;
// }
} 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);
}
});
});
}
};
module.exports = common;
... ...
/**
*
* @author: jiangfeng<jeff.jiang@yoho.cn>
* @date: 16/7/22
*/
'use strict';
const Sign = {
raw(args) {
let keys = Object.keys(args);
keys = keys.filter(k => {
return args[k] === '' || args[k] === 'undefined' ? false : true;
}).sort();
return keys.map(k => {
return k + '=' + decodeURI(args[k]);
}).join('&');
},
rawUncode(args) {
let keys = Object.keys(args);
keys = keys.filter(k => {
return args[k] === '' || args[k] === 'undefined' ? false : true;
}).sort();
return keys.map(k => {
return k.toLowerCase() + '=' + args[k];
}).join('&');
}
};
module.exports = Sign;
... ...
/**
*
* @author: jiangfeng<jeff.jiang@yoho.cn>
* @date: 16/9/8
*/
'use strict';
const ServiceAPI = global.yoho.ServiceAPI;
const helpers = global.yoho.helpers;
const Wechat = {
pay(user, order, info) {
return ServiceAPI.get('payment/weixin_data', {
order_code: order.order_code,
payment_code: info.id,
app_key: 'blkpc'
}).then(result => {
if (result && result.code === 200 && result.data) {
let url = `/shopping/pay/online/weixin?url=${result.data.codeUrl}&code=${order.order_code}`;
return {
code: 200,
data: {
href: helpers.urlFormat(url)
}
};
} else {
return {
code: 400,
message: result.message
};
}
});
}
};
module.exports = Wechat;
... ...
/**
* 各种支付的入口
* TAR NOTE: 本项目中仅支持支付宝和微信支付,其他支付方式需调试
* @author: jiangfeng<jeff.jiang@yoho.cn>
* @date: 16/7/22
*/
'use strict';
const PayModel = require('../models/pay');
const Alipay = require('./pay/alipay');
const Alibank = require('./pay/alibank');
const Wechat = require('./pay/wechat');
const Promise = require('bluebird');
const co = Promise.coroutine;
const logger = global.yoho.logger;
const Payment = {
pay(user, order, payType, protocol) {
return co(function*() {
let result = {
code: 400,
message: '获取支付方式信息失败'
};
let paymentPars = payType.split('_');
let payInfo;
let bankCode = '';
if (paymentPars.length !== 2) {
return result;
}
if (!order.order_code) {
result.message = '没有找到该订单';
return result;
}
if (order.is_cancel && order.is_cancel === 'Y') {
result.message = '该订单已经取消';
return result;
}
// if (order.pay_expire && common.getPayExpireMin(order.pay_expire) <= 0) {
// result.message = '当前订单不可支付'; // 该订单已超过2个小时
// return result;
// }
let method = paymentPars[0] * 1;
if (method === PayModel.payments.wechat) {
// 如果是微信支付,不需要调用获取支付方式详情接口
result = yield Wechat.pay(user, order, { id: PayModel.payments.wechat });
} else {
payInfo = yield PayModel.getPaymentInfo(method);
if (!payInfo.payParams) {
return result;
}
switch (payInfo.id) {
case PayModel.payments.alipay:
result = Alipay.pay(user, order, payInfo, protocol);
break;
case PayModel.payments.alibank:
bankCode = paymentPars[1];
payInfo.bankCode = bankCode; // 设置默认银行
result = Alibank.pay(user, order, payInfo, protocol);
break;
default:
break;
}
}
logger.info(`pay to url, params = ${JSON.stringify(result)}`);
if (result.code === 200) {
let updateInfo = yield Payment.beforePay(user, order, method, bankCode);
if (updateInfo && updateInfo.code !== 200) {
return updateInfo;
}
}
return result;
})();
},
beforePay(user, order, method, bankCode) {
return Promise.all([
PayModel.updateOrderPayment(order.order_code, method, user.uid),
PayModel.getBankByOrder(order.order_code)
]).then(result => {
let paymentRecord = result[0];
let bankRecord = result[1];
if (!paymentRecord || paymentRecord.code !== 200) {
let message = paymentRecord && paymentRecord.message ? paymentRecord.message : '系统繁忙,请稍后再试';
return { code: 400, message: message };
}
if (bankRecord && bankRecord.bankCode) {
return PayModel.updateOrderPayBank(order.order_code, method, bankCode);
} else {
return PayModel.setOrderPayBank(order.order_code, method, bankCode);
}
}).catch(e => {
logger.error('update order pay info error.', e);
return Promise.resolve({
code: 400,
message: '更新订单支付信息失败'
});
});
},
afterPay(query, payId, user, sessionKey) {
return co(function*() {
let payInfo = yield PayModel.getPaymentInfo(payId);
let payResult = {};
let payData = {};
let payName = '';
if (payId === PayModel.payments.alipay) {
payResult = Alipay.notify(query, payInfo);
} else if (payId === PayModel.payments.alibank) {
payResult = Alibank.notify(query, payInfo);
}
payResult.bankName = payName = payResult.bankName || payInfo.payName || '';
payResult.bankCode = payResult.bankCode || payInfo.pay_code || '';
// 记录日志
logger.info(`\r\n\r\n pay back confirmreq = ${JSON.stringify({
query: query,
payId: payId,
user: user,
payResult: payResult
})}`);
if (payResult && payResult.payResult === 200) {
if (payResult.orderCode) {
logger.info('pay back confirm');
yield PayModel.sendPayConfirm(payResult.orderCode, payId, user.uid);
}
payData = yield PayModel.procOrderData(payResult, user.uid, sessionKey);
} else {
payData = {
code: 500,
message: '支付失败'
};
}
payData.payName = payName;
return payData;
})();
}
};
module.exports = Payment;
... ...
'use strict';
const _ = require('lodash');
const crypto = global.yoho.crypto;
const processInvoiceData = (orderInfo, mobile, addresslist) => {
let invoices_title = '';
let invoiceType = '7';
let invoices_type = '2';
let invoice_Top = '个人';
// 用户手机号处理
if (orderInfo.receiverMobile && orderInfo.isModifyTel) {
mobile = orderInfo.receiverMobile;
} else {
_.forEach(addresslist, addressValue => {
if (addressValue.address_id === crypto.encryption('', orderInfo.addressId)) {
mobile = addressValue.mobile;
}
});
}
// 发票信息处理
if (orderInfo.invoiceType && orderInfo.invoiceTitle) {
invoices_title = orderInfo.invoiceText;
invoiceType = orderInfo.invoiceType;
invoices_type = orderInfo.invoicesType * 1;
invoice_Top = orderInfo.invoiceTitle;
}
return {
invoiceNotice: '发票须知',
phone: mobile ? mobile : '', // TODO 字符串替换 ****
completeTel: mobile,
isCompany: invoice_Top !== '单位',
companyName: invoices_title,
isPaper: invoices_type === 1,
invoicesType: [
{
id: '2',
type: '电子发票',
choosed: !invoices_type || invoices_type === 2,
},
{
id: '1',
type: '纸质发票',
choosed: invoices_type === 1
}
],
invoiceTitle: [
{
type: '个人',
choosed: invoice_Top === '个人'
},
{
type: '单位',
choosed: invoice_Top === '单位'
}
],
content: [
{
choosed: !invoiceType || invoiceType === 7,
id: 7,
text: '服装'
},
{
choosed: invoiceType === 9,
id: 9,
text: '配件'
},
{
choosed: invoiceType === 11,
id: 11,
text: '日用品'
},
{
choosed: invoiceType === 3,
id: 3,
text: '办公用品'
},
{
choosed: invoiceType === 6,
id: 6,
text: '体育用品'
},
{
choosed: invoiceType === 10,
id: 10,
text: '数码产品'
},
]
};
};
module.exports = {
processInvoiceData
};
... ...
/**
* 支付相关api调用
* @author: jiangfeng<jeff.jiang@yoho.cn>
* @date: 2016/07/18
*/
'use strict';
const api = global.yoho.API;
// 获取支付宝等平台支付方式列表
const getPayProvider = () => {
return api.get('', {
method: 'web.SpaceOrders.getPaymentList'
}, {cache: true});
};
// 获取单个支付方式相关详细信息
const getPaymentInfo = (id) => {
return api.get('', {
method: 'web.SpaceOrders.getPaymentById',
id: id
}, {cache: true});
};
/* 获取上次使用的支付方式*/
const getBankByOrder = (code) => {
return api.get('', {
method: 'web.SpaceOrders.getOrderPayBank',
orderCode: code
});
};
/* 记录支付方式*/
const setOrderPayBank = (code, payment, bankCode) => {
return api.get('', {
method: 'web.SpaceOrders.addOrderPayBank',
orderCode: code,
payment: payment,
bankCode: bankCode
});
};
/* 更改支付方式*/
const updateOrderPayBank = (code, payment, bankCode) => {
return api.get('', {
method: 'web.SpaceOrders.modifyOrderPayBank',
orderCode: code,
payment: payment,
bankCode: bankCode
});
};
/* 发送支付确认*/
const sendPayConfirm = (code, payment, uid) => {
return api.get('', {
method: 'app.SpaceOrders.payConfirm',
order_code: code,
payment_id: payment,
uid: uid
});
};
const sendMessage = (mobile, template, codes) => {
return api.get('', {
method: 'app.message.sendMsg',
mobile: mobile,
template: template,
codes: codes
});
};
module.exports = {
getPayProvider,
getPaymentInfo,
getBankByOrder,
setOrderPayBank,
updateOrderPayBank,
sendPayConfirm,
sendMessage
};
... ...
/**
* 支付成功页
* 支付
* @author: jing.li<jing.li@yoho.cn>
* @date: 2016/10/25
*/
... ... @@ -10,7 +10,18 @@ const api = global.yoho.API;
const serviceAPI = global.yoho.ServiceAPI;
const utils = '../../../utils';
const productProcess = require(`${utils}/product-process`);
const payApi = require('./pay-api');
const helpers = global.yoho.helpers;
const _ = require('lodash');
const co = require('bluebird').coroutine;
const logger = global.yoho.logger;
// 支付方式
const payments = {
alipay: 33,
wechat: 36,
alibank: 42
};
// 资源位
const _getBanner = (param) => {
... ... @@ -51,7 +62,8 @@ const _getOtherDetail = (param) => {
return api.get('', {
method: 'app.SpaceOrders.detail',
uid: param.uid,
order_code: param.orderCode
order_code: param.orderCode,
session_key: param.sessionKey
}, {
code: 200
}).then((result) => {
... ... @@ -73,7 +85,7 @@ const _getOthersBuy = (param) => {
goodSkn = result[0].data.order_goods[0].product_skn;
}
return _getOthersBuy2(Object.assign(param, {skn: goodSkn}));
return _getOthersBuy2(Object.assign(param, { skn: goodSkn }));
}).then((result) => {
... ... @@ -82,29 +94,224 @@ const _getOthersBuy = (param) => {
};
/**
* 支付中心
* @param params
* 获取订单支付银行信息
* @param id
*/
const payCenter = (params) => {
return Promise.resolve({
payList: [
{
const getBankByOrder = (id) => {
return co(function*() {
let result = yield payApi.getBankByOrder(id);
if (result && result.code === 200 && result.data) {
return result.data;
}
return {};
})();
};
/**
* 设置订单支付银行
* @param code
* @param payment
* @param bankCode
*/
const setOrderPayBank = (code, payment, bankCode) => {
return co(function*() {
let data = yield payApi.setOrderPayBank(code, payment, bankCode);
return data;
})();
};
/**
* 获取支付方式的相关参数, (密钥等信息)
* @param id
*/
const getPaymentInfo = (id) => {
return co(function*() {
let result = yield payApi.getPaymentInfo(id);
if (result && result.code === 200 && result.data) {
return result.data;
}
return {};
})();
};
/**
* 支付确认
* @param code
* @param payment
* @param uid
*/
const sendPayConfirm = (code, payment, uid) => {
return co(function*() {
let data = yield payApi.sendPayConfirm(code, payment, uid);
return data;
})();
};
/**
* 更新订单支付方式
* @param code
* @param payment
* @param uid
* @returns {*}
*/
const updateOrderPayment = (code, payment, uid) => {
return api.get('', {
method: 'app.SpaceOrders.updateOrdersPaymentByCode',
order_code: code,
payment: payment,
uid: uid
});
};
/**
* 更新订单支付银行
* @param code
* @param payment
* @param bankCode
*/
const updateOrderPayBank = (code, payment, bankCode) => {
return co(function*() {
let data = yield payApi.updateOrderPayBank(code, payment, bankCode);
return data;
})();
};
/**
* 支付成功,前端回调时,处理订单信息
* @param payResult
* @param uid
* @param sessionKey
*/
const procOrderData = (payResult, uid, sessionKey) => {
return co(function*() {
let orderCode = payResult.orderCode;
let result = { code: 400, message: '' };
if (!orderCode) {
result.message = '未查到订单信息,订单状态更新失败!';
return result;
} else {
let orderInfo = yield _getOtherDetail({
uid: uid,
orderCode: orderCode,
sessionKey: sessionKey
});
if (orderInfo && orderInfo.data) {
let order = orderInfo.data;
let amount = order.payment_amount;
if (order.is_cancel === 'Y') {
logger.warn('front pay success but order is cancel.', { payResult: payResult, order: order });
payApi.sendMessage(order.mobile, 'error_sms', '支付成功,但订单已取消,订单号为' + orderCode);
return { code: 417, message: '支付成功,但订单已取消,需联系客服!' };
}
if (order.payment_status === 'N') {
logger.warn('front pay success but may be notify fail');
}
if (_.round(parseFloat(amount), 2) !== _.round(parseFloat(payResult.totalFee), 2)) {
logger.warn('front pay success but the amount is not same.', { payResult: payResult, order: order });
return {
code: 415,
message: '支付金额与订单金额不一致,订单状态更新失败!'
};
}
return {
code: 200,
message: '支付成功,请等待发货',
data: {
order: order
}
};
} else {
result.message = '未查到订单信息,订单状态更新失败!';
}
}
return result;
})();
};
/**
* 支付相关的数据处理函数
*/
const payTool = {
/**
* 支持的支付方式列表
* @returns {[*,*]}
*/
payAppInfo(orderCode) {
return [{
appIcon: '',
payLink: helpers.urlFormat('/shopping/pay/index'),
payLink: helpers.urlFormat('/cart/index/new/pay/goalipay', {
payment: payments.alipay + '_platform',
order_code: orderCode
}),
appId: 'alipay',
app: '支付宝支付',
hint: '支付宝钱包支付',
subHint: '推荐支付宝用户使用'
},
{
}, {
appIcon: '',
payLink: '',
appId: 'weixin',
app: '微信支付',
hint: '推荐使用',
subHint: ''
}];
},
/**
* 计算购买商品总数量
* @param goodsArray
* @returns {number}
* @private
*/
calBuyNumCount(goodsArray) {
let buyNumCount = 0;
if (_.isArray(goodsArray)) {
_.forEach(goodsArray, value => {
buyNumCount = value.buy_number ? parseInt(value.buy_number, 10) : 0;
});
}
return buyNumCount;
}
]
};
/**
* 支付中心
* @param params
*/
const payCenter = (params) => {
return _getOtherDetail({
uid: params.uid,
orderCode: params.orderCode
}).then(result => {
let resultData = _.get(result, 'data', {});
return {
payAppInfo: payTool.payAppInfo(params.orderCode),
orderCode: params.orderCode,
hasWxShare: true,
orderTotal: resultData.payment_amount || 0,
orderTotalFormat: parseInt(resultData.payment_amount, 10),
orderCount: payTool.calBuyNumCount(resultData.order_goods),
uid: params.uid
};
});
};
... ... @@ -181,6 +388,15 @@ const getPayAli = (param) => {
};
module.exports = {
payments,
getOtherDetail: _getOtherDetail,
updateOrderPayment,
updateOrderPayBank,
getBankByOrder,
getPaymentInfo,
setOrderPayBank,
sendPayConfirm,
procOrderData,
payCenter,
getPayCod,
getPayAli
... ...
... ... @@ -25,8 +25,10 @@ router.post('/index/seckill/submit', seckill.submit);
router.get('/index/count', countController.cartCount);
router.get('/paySuccess/payCod', payController.payCod);// 支付成功,货到付款
router.get('/index/new/pay/center', payController.payCenter);// 支付成功,支付宝付款
router.get('/index/new/pay/aliwapreturn', payController.payAli);// 支付成功,支付宝付款
router.get('/index/new/pay', authMW, payController.payCenter);// 支付中心
router.get('/index/new/pay/goalipay', authMW, payController.goAlipay);// 跳支付宝支付
router.get('/index/new/pay/aliwapreturn', authMW, payController.payAli);// 支付宝付款支付成功
router.get('/index/new/orderEnsure', authMW, order.orderEnsure); // 订单结算
router.get('/index/new/selectCoupon', authMW, order.selectCoupon); // 选择优惠券 页面
... ...
... ... @@ -132,7 +132,7 @@
<input type="hidden" class="user-mobile" value="{{userMobile}}" />
<span class="title">发票</span>
<span class="iconfont checkbox {{#if needInvoice}}icon-cb-radio{{else}}icon-radio{{/if}}"></span>
<a id="invoice" class="invoice-info" href="/cart/index/invoiceInfo">
<a id="invoice" class="invoice-info" href="/cart/index/new/invoiceInfo">
<span class="title">发票信息</span>
<span class="invoice-type"><i class="iconfont">&#xe614;</i></span>
</a>
... ...
... ... @@ -3,7 +3,6 @@
<input id='ordercode' type="hidden" value="{{orderCode}}">
{{/if}}
<div class="payapp-list">
{{log payAppInfo}}
{{# payAppInfo}}
{{#if payLink}}
<a href="{{payLink}}">
... ...
<div class="invoice-info-page yoho-page">
<ul class="invoice-form">
<li>
<span class="title">发票类型:</span>
<div class="invoice-type">
{{#invoicesType}}
<span {{#if choosed}}class="on"{{/if}} data-id="{{id}}">{{type}}</span>
{{/invoicesType}}
</div>
</li>
<li>
<span class="title">发票抬头:</span>
<div class="invoice-top">
{{#invoiceTitle}}
<span {{#if choosed}}class="on"{{/if}}><i class="iconfont choose {{#if choosed}}icon-cb-radio{{else}}icon-radio{{/if}}"></i>{{type}}</span>
{{/invoiceTitle}}
</div>
</li>
<li {{#isPaper}}style="display: none;"{{/isPaper}} class="tel-area">
<span class="title"><i class="txt-point">*</i>发票人手机:</span>
<span class="phone">
<input type="hidden" class="copy-tel" value="{{completeTel}}">
<input type="text" name="tel" data-tel="{{completeTel}}" class="tel {{#phone}}istel{{/phone}}" value="{{phone}}" placeholder="可通过手机号在发票服务平台查询">
</span>
</li>
<li class="company-area" {{#isCompany}}style="display: none;"{{/isCompany}}><input type="text" name="company" class="company" value="{{companyName}}" placeholder="填写单位名称" maxlength="30"></li>
</ul>
<ul class="invoice-cont">
<li class="cont-title">
<span>发票内容:</span>
<span class="choose-cont" data-id=""></span>
</li>
{{#each content}}
<li><span class="iconfont choose {{#if choosed}}icon-cb-radio{{else}}icon-radio{{/if}}" data-id="{{id}}"></span>{{text}}</li>
{{/each}}
</ul>
<div class="btn-area"><span class="confirm-btn">确认</span></div>
<div class="invoice-notice">
<div class="mask-bg"></div>
<div class="notice-area">
<div class="notice-cont">
<h2>发票须知</h2>
<p>1、发票金额不含优惠券/有货币/红包/优惠码/运费,只包含商品实付金额</p>
<p>2、电子发票:是税局认可的有效收付款凭证,其法律效力、基本用途及使用规定同纸质发票,如需纸质发票可自行下载打印</p>
</div>
<div class="think-ok">我知道了</div>
</div>
</div>
<input type="hidden" class="edit-flag" value="false" />
<input type="hidden" class="address-more" value="{{addressMore}}" />
</div>
... ...
... ... @@ -21,3 +21,10 @@ exports.queryProfile = (uid) => {
return api.get('', params, options);
};
exports.addressTextData = (uid) => {
return api.get('', {
method: 'app.address.get',
uid: uid
});
};
... ...
... ... @@ -16,21 +16,29 @@ module.exports = {
siteUrl: '//m.yohobuy.com',
assetUrl: '//127.0.0.1:5001',
domains: {
// api: 'http://api-test3.yohops.com:9999/',
// service: 'http://service-test3.yohops.com:9999/',
// liveApi: 'http://testapi.live.yohops.com:9999/',
// singleApi: 'http://api-test3.yohops.com:9999/',
// imSocket: 'ws://im.yohobuy.com:10240',
// imCs: 'http://im.yohobuy.com/api',
// imServer: 'http://im.yohobuy.com/server'
api: 'http://api-test3.yohops.com:9999/',
service: 'http://service-test3.yohops.com:9999/',
liveApi: 'http://testapi.live.yohops.com:9999/',
singleApi: 'http://api-test3.yohops.com:9999/',
imSocket: 'ws://im.yohobuy.com:10240',
imCs: 'http://im.yohobuy.com/api',
imServer: 'http://im.yohobuy.com/server',
api: 'http://dev-api.yohops.com:9999/',
service: 'http://service.yoho.cn/',
liveApi: 'http://api.live.yoho.cn/',
singleApi: 'http://single.yoho.cn/',
imSocket: 'ws://imsocket.yohobuy.com:10000',
imCs: 'http://imhttp.yohobuy.com/api',
imServer: 'http://imhttp.yohobuy.com/server'
// api: 'http://api.yoho.cn/',
// service: 'http://service.yoho.cn/',
// liveApi: 'http://api.live.yoho.cn/',
// singleApi: 'http://single.yoho.cn/',
// imSocket: 'ws://imsocket.yohobuy.com:10000',
// imCs: 'http://imhttp.yohobuy.com/api',
// imServer: 'http://imhttp.yohobuy.com/server'
// api: 'http://dev-api.yohops.com:9999/',
// service: 'http://service.yoho.cn/',
// liveApi: 'http://api.live.yoho.cn/',
// singleApi: 'http://single.yoho.cn/',
// imSocket: 'ws://imsocket.yohobuy.com:10000',
// imCs: 'http://imhttp.yohobuy.com/api',
// imServer: 'http://imhttp.yohobuy.com/server'
},
subDomains: {
host: '.m.yohobuy.com',
... ... @@ -86,7 +94,20 @@ module.exports = {
appSecret: 'ce21ae4a3f93852279175a167e54509b'
}
},
zookeeperServer: '192.168.102.168:2188'
zookeeperServer: '192.168.102.168:2188',
alipayConfig: {
payUrl: 'https://mapi.alipay.com/gateway.do',
service: 'alipay.wap.create.direct.pay.by.user',
partner: '2088701661478015',
inputCharset: 'utf-8',
notifyUrl: 'payment/alipay_notify',
returnUrl: '/shopping/pay/aliwapreturn',
signType: 'MD5',
paymentType: '1',
alipayKey: 'kcxawi9bb07mzh0aq2wcirsf9znusobw',
sellerMail: 'zfb@yoho.cn',
merchantUrl: 'http://m.yohobuy.com/home/orders/detail?order_code='
}
};
if (isProduction) {
... ...
... ... @@ -43,6 +43,7 @@
"request-promise": "^3.0.0",
"serve-favicon": "^2.3.2",
"uuid": "^2.0.3",
"xml2js": "^0.4.17",
"yoho-node-lib": "0.2.2",
"yoho-zookeeper": "^1.0.4"
},
... ...
/**
* 发票信息
* @author: wsl<shuiling.wang@yoho.cn>
* @date: 2016/6/14
*/
var $ = require('yoho-jquery'),
tip = require('../plugin/tip'),
dialog = require('../plugin/dialog'),
order = require('./order-info');
var $invoiceNotice = $('.invoice-notice'),
$companyArea = $('.company-area'),
$editFlag = $('.edit-flag'),
$chooseCont = $('.choose-cont'),
$invoiceType = $('.invoice-type'),
$tel = $('.tel'),
$company = $('.company'),
$telArea = $('.tel-area'),
orderInfo = order.orderInfo,
$chooseContLi = $('.invoice-cont').find('.icon-cb-radio').parent(),
$copyTel = $('.copy-tel'),
isModifyTel = false;
var myreg = /^(((13[0-9]{1})|(14[0-9]{1})|(15[0-9]{1})|(17[0-9]{1})|(18[0-9]{1}))+\d{8})$/,
linkUrl = $('.address-more').val() || '/cart/index/orderEnsure?cartType=ordinary';
var C_ID = window._ChannelVary[window.cookie('_Channel')] || 1;
require('../common');
if (window.getUid() !== orderInfo('uid')) {
order.init();
window.location.reload();
}
// 单选效果
function chooseAction(pDom, dom) {
if (dom.hasClass('icon-cb-radio')) {
return;
} else {
pDom.find('.choose').removeClass('icon-cb-radio icon-radio').addClass('icon-radio');
dom.removeClass('icon-radio').addClass('icon-cb-radio');
dom.parent().addClass('on');
dom.parent().siblings().removeClass('on');
$editFlag.val('true');
}
}
// 确认表单事件
function confirmAction() {
var type = $invoiceType.find('.on').data('id'),
title = $('.invoice-top').find('.on').text(),
tel = $tel.attr('data-tel'),
company = $company.val(),
cont = $chooseCont.data('id');
if ($editFlag.val() === 'true') {
if (type === 2 && !myreg.test($tel.attr('data-tel'))) {
tip.show('请输入正确手机号');
$tel.focus();
return false;
} else if (title === '单位' && company.length === 0) {
tip.show('请填写发票抬头');
$company.focus();
return false;
} else if (title === '单位' && company.length > 30) {
tip.show('发票抬头不得超过30个汉字');
$company.focus();
return false;
} else {
dialog.showDialog({
dialogText: '确认保存修改内容?',
hasFooter: {
leftBtnText: '取消',
rightBtnText: '确定'
}
}, function() {
orderInfo('invoiceText', (title === '单位' ? company : ''));
orderInfo('invoiceType', cont);
orderInfo('receiverMobile', tel);
orderInfo('invoicesType', type);
orderInfo('invoiceTitle', title);
if (isModifyTel && $copyTel !== tel) {
orderInfo('isModifyTel', true);
} else {
orderInfo('isModifyTel', false);
}
dialog.showDialog({
dialogText: '保存成功',
autoHide: true,
fast: true
});
window.location.href = linkUrl;
}, function() {
window.location.href = linkUrl;
});
}
} else {
window.location.href = linkUrl;
}
}
$chooseCont.html($chooseContLi.text()).attr('data-id', $chooseContLi.find('span').data('id'));
// 发票抬头、发票内容选择
$('.invoice-top span, .invoice-cont li').not('.invoice-cont .cont-title').on('touchstart', function() {
chooseAction($(this).parent(), $(this).find('.choose'));
if ($(this).parent().hasClass('invoice-cont')) {
$chooseCont.html($(this).text()).attr('data-id', $(this).find('span').data('id'));
}
if ($(this).text() === '单位') {
$companyArea.slideDown();
}
if ($(this).text() === '个人') {
$companyArea.slideUp();
}
});
// 发票类型选择
$('.invoice-type span').on('touchstart', function() {
if ($(this).hasClass('on')) {
return;
} else {
$(this).addClass('on').siblings().removeClass('on');
$editFlag.val('true');
// 纸质发票不显示手机号
if ($(this).index() === 1) {
$telArea.slideUp();
} else {
$telArea.slideDown();
}
}
});
// 发票须知
$('.invoice-btn').on('touchstart', function() {
$invoiceNotice.fadeIn();
return false;
});
// 关闭发票须知弹框
$('.think-ok, .mask-bg').on('touchstart', function() {
$invoiceNotice.fadeOut();
});
// 电话清空
$('.istel').one('input', function() {
$(this).val('').removeClass('istel');
});
$tel.on('input', function() {
$(this).attr('data-tel', $(this).val());
$editFlag.val('true');
isModifyTel = true;
});
$company.on('input', function() {
$editFlag.val('true');
});
// 确认及返回事件
$('.confirm-btn, .nav-back').on('touchstart', function(e) {
setTimeout(function() {
if (window._yas && window._yas.sendCustomInfo) {
window._yas.sendCustomInfo({
op: 'YB_SC_INVOICE_INFO_SAVE',
param: JSON.stringify({
C_ID: C_ID,
INVOICE_TYPE: $invoiceType.find('.on').data('id'),
INVOICE_TITLE: $('.invoice-top').find('.on').text(),
INVOICE_CONTENT: $chooseCont.data('id')
})
}, true);
}
}, 200);
e.preventDefault();
confirmAction();
});
// initData();
... ...
... ... @@ -590,7 +590,7 @@
span {
display: inline-block;
width: 130px;
width: 160px;
}
}
... ...