pay.js 12.6 KB
/**
 * 订单支付
 * @author: xiaoxiao.hao<xiaoxiao.hao@yoho.cn>
 * @date: 2016/07/18
 */

'use strict';

const PayApi = require('./pay-api');
const Promise = require('bluebird');
const payHelpersBank = require('./../helpers/bank');
const logger = global.yoho.logger;
const _ = require('lodash');
const helpers = global.yoho.helpers;
const FRAUD_CONTENT_CODE = '78d0fb6c97d691863286edcb4d8abfa9';

module.exports = class extends global.yoho.BaseModel {
    constructor(ctx) {
        super(ctx);

        this.payments = {
            alipay: 2, // 支付宝
            wechat: 21, // 微信支付
            alibank: 12, // 支付宝支联
            unionpay: 25, // 银联支付
            chinabank: 4, // 网银在线
            tenpay: 1, // 财付通
            delivery: 3 // 货到付款和0元订单
        };

        this.payApiModel = new PayApi(this.ctx);
    }

    /**
     * [更新订单支付方式]
     * @param  {[type]} code    [订单号]
     * @param  {[type]} payment [支付方式]
     * @param  {[type]} uid     [用户uid]
     * @return {[type]}         [{}]
     */
    updateOrderPayment(code, payment, uid) {
        return this.payApiModel.updateOrderPayment(code, payment, uid);
    }

    /**
     * [订单详情]
     * @param  {[type]} uid       [用户uid]
     * @param  {[type]} orderCode [订单号]
     * @return {[type]}           [{}]
     */
    orderDetail(uid, orderCode) {
        return this.payApiModel.orderDetail(uid, orderCode);
    }

    /**
     * 获取在线支付方式
     * @returns {*|Promise.<TResult>}
     */
    getOnlinePayProvider() {
        return this.payApiModel.getPayProvider().then(result => {
            let payPattern = [], nav = [];

            if (!(result.code && result.code === 200)) {
                return payPattern;
            }

            // 处理支付宝等平台数据
            _.each(result.data, val => {
                // 去除icon为空的
                if (_.isEmpty(val.payIcon)) {
                    return true;
                }

                // 财付通和网银关闭
                if (val.id === 4 || val.id === 1) {
                    return true;
                }

                nav.push({
                    id: val.id,
                    name: val.payName,
                    value: val.id + '_platform',
                    img: val.payIcon.replace('http://', '//')
                });
            });

            payPattern.push({
                name: '支付宝等平台',
                children: nav
            });

            // 处理使用银行卡数据
            nav = [];
            _.each(payHelpersBank.getList(), (val, key) => {
                nav.push({
                    id: this.payments.alibank,
                    name: val.name,
                    value: this.payments.alibank + '_' + key,
                    img: val.ico
                });
            });
            payPattern.push({
                name: '使用银行卡',
                children: nav
            });

            return payPattern;
        });
    }

    /**
     * 获取订单详情
     * @param uid
     * @param code
     */
    getOrderInfo(uid, code) {
        return this.orderDetail(uid, code).then(data => {
            return _.get(data, 'data', {});
        });
    }

    /**
     * 获取订单支付银行信息
     * @param id
     */
    getBankByOrder(id) {
        return this.payApiModel.getBankByOrder(id).then(data => {
            return _.get(data, 'data', {});
        });
    }

    /**
     * 获取支付页数据
     * @param uid
     * @param code
     */
    getPayInfo(uid, code) {
        return Promise.all([
            this.getOnlinePayProvider(),
            this.getOrderInfo(uid, code),
            this.getBankByOrder(code),
            this.payApiModel.getOrderCountByUid(uid)
        ]).then(payment => {
            let paymentId = parseInt(payment[2].payment || 0, 10);
            let orderInfo = payment[1] || {};
            let findIndex;
            let payDefault;

            // 渲染选择的默认支付方式
            if (paymentId === this.payments.alibank && payment[0][1] && payment[2]) { // 银行支付
                findIndex = _.findIndex(
                    payment[0][1].children,
                    {value: this.payments.alibank + '_' + payment[2].bankCode}
                );
                findIndex = findIndex > 0 ? findIndex : 0;
                payment[0][1].selected = true;
                payment[0][1].children[findIndex].selected = true;

                payDefault = payment[0][1].children[findIndex];
            } else if (payment[0] && payment[0][0]) { // 支付宝等平台
                findIndex = _.findIndex(payment[0][0].children, {id: paymentId});
                findIndex = findIndex > 0 ? findIndex : 0;
                payment[0][0].selected = true;
                payment[0][0].children[findIndex].selected = true;

                payDefault = payment[0][0].children[findIndex];
            }

            if (orderInfo.order_code) {
                // 订单处理
                if (orderInfo.attribute === 3) {
                    orderInfo.deliveryTimes = '自动发货 - 在您支付成功后,系统将立即为您发放二维码,您可以在您的订单中查看。';
                } else {
                    orderInfo.deliveryTimes = orderInfo.delivery_time || '';
                }

                // 用于订单统计
                orderInfo.uid = uid;
                orderInfo.orderCount = 0;
                if (payment[3].code === 200 && payment[3].data) {
                    orderInfo.orderCount = payment[3].data.count || 0;
                }
                orderInfo.isOldUser = orderInfo.orderCount > 1;
                orderInfo.ordersGoodsNums = orderInfo.order_goods.length;
                let sknList = [];
                let skuList = [];
                let goodsData = [];
                let pinyouGoodsArr = [];

                _.each(orderInfo.order_goods, function(el) {
                    sknList.push(el.product_skn);
                    skuList.push(el.product_sku);
                    goodsData.push({
                        goods_name: el.product_name,
                        product_sku: el.product_sku,
                        price: el.goods_price,
                        number: el.buy_number
                    });
                    pinyouGoodsArr.push(`${el.product_skn},${el.buy_number}`);
                });
                orderInfo.sknList = sknList;
                orderInfo.skuList = skuList;
                orderInfo.goodsData = goodsData;
                orderInfo.goodsDatas = JSON.stringify(goodsData);

                // 品友统计需要的商品数据
                orderInfo.pinyouGoods = pinyouGoodsArr.join(';');
            }

            return {
                pay: payment[0],
                order: orderInfo,
                payDefault: payDefault
            };
        });
    }

    /**
     * 获取支付方式的相关参数, (密钥等信息)
     * @param id
     */
    getPaymentInfo(id) {
        return this.payApiModel.getPaymentInfo(id).then(data => {
            return _.get(data, 'data', {});
        });
    }

    /**
     * 设置订单支付银行
     * @param code
     * @param payment
     * @param bankCode
     */
    setOrderPayBank(code, payment, bankCode) {
        return this.payApiModel.setOrderPayBank(code, payment, bankCode);
    }

    /**
     * 更新订单支付银行
     * @param code
     * @param payment
     * @param bankCode
     */
    updateOrderPayBank(code, payment, bankCode) {
        return this.payApiModel.updateOrderPayBank(code, payment, bankCode);
    }

    /**
     * 支付确认
     * @param code
     * @param payment
     * @param uid
     */
    sendPayConfirm(code, payment, uid) {
        return this.payApiModel.sendPayConfirm(code, payment, uid);
    }

    /**
     * [埋点数据公共处理]
     * @param  {[type]} orderInfo [订单详情]
     * @param  {[type]} payId [支付方式id]
     * @param  {[type]} payResultStatus [支付成功状态]
     * @return {[type]}           [{}]
     */
    _point(orderInfo, payId, payResultStatus) {
        let sknArr = [];
        let skuArr = [];

        _.each(orderInfo.order_goods, function(el) {
            sknArr.push(el.product_skn);
            skuArr.push(el.product_sku);
        });

        return {
            order_code: orderInfo.order_code,
            payResult: payResultStatus, // 1支付成功,2支付失败
            amount: orderInfo.payment_amount,
            payStyle: payId, // 支付方式id
            proSkn: sknArr.join(','),
            proSku: skuArr.join(',')
        };
    }

    /**
     * [公共支付成功数据处理]
     * @param  {[type]} orderInfo [订单信息]
     * @param  {[type]} fraudData [资源位数据]
     * @param  {[type]} payId [支付方式ID]
     * @return {[type]}           [{}]
     */
    _execOrderData(orderInfo, fraudData, payId) {
        let fraud = _.result(_.find(fraudData, {template_name: 'text'}), 'data') || {};

        return {
            paymentTypes: (orderInfo.payment_type === 1 ? '在线支付' : '货到付款'),
            multiPackage: orderInfo.is_multi_package === 'Y',
            ordersUrl: helpers.urlFormat('/home/orders'),
            vipUrl: helpers.urlFormat('/help/detail', {id: 9}),
            returnGoodsUrl: helpers.urlFormat('/help/detail', {id: 49}),
            yohoCoinUrl: helpers.urlFormat('/help/detail', {id: 105, contId: 233}),
            detailUrl: helpers.urlFormat('/home/orders/detail', {
                orderCode: orderInfo.order_code
            }),
            packageTitle: orderInfo.package_title || '商品需要品牌商调货',
            fraudTip: fraud.text || '',
            criteo: {// criteo统计代码有关数据
                order_code: orderInfo.order_code,
                items: orderInfo.order_goods
            },
            point: this._point(orderInfo, payId, 1)
        };
    }

    /**
     * 支付成功,前端回调时,处理订单信息
     * @param payResult
     * @param uid
     */
    procOrderData(payResult, uid, payId) {
        let orderCode = payResult.orderCode;
        let result = {code: 400, message: ''};

        if (!orderCode) {
            result.message = '订单不存在';
            return result;
        }

        return Promise.all([
            this.orderDetail(uid, orderCode),
            this.payApiModel.getResourceData(FRAUD_CONTENT_CODE)
        ]).then(procData => {
            let orderInfo = procData[0].code === 200 && procData[0].data;

            if (!orderInfo) {
                result.message = '订单不存在!';
                return result;
            }

            if (orderInfo.is_cancel === 'Y') {
                logger.warn('front pay success but order is cancel.', {payResult: payResult, order: orderInfo});
                return {code: 417, message: '支付成功,但订单已取消,需联系客服!', point: this._point(orderInfo, payId, 2)};
            }

            if (orderInfo.payment_status === 'N') {
                logger.warn('front pay success but may be notify fail');
            }

            if (_.round(parseFloat(orderInfo.payment_amount), 2) !== _.round(parseFloat(payResult.totalFee), 2)) {
                logger.warn('front pay success but the amount is not same.', {payResult: payResult, order: orderInfo});
                return {
                    code: 415,
                    message: '支付金额与订单金额不一致,订单状态更新失败!',
                    point: this._point(orderInfo, payId, 2)
                };
            }

            return {
                code: 200,
                message: '支付成功,请等待发货',
                data: {
                    order: Object.assign(
                        orderInfo,
                        this._execOrderData(orderInfo, procData[1] && procData[1].data || {}, payId)
                    )
                }
            };

        });
    }

    /**
     * [0元订单或者货到付款-成功处理]
     * @param  {[type]} orderInfo [订单详情]
     * @param  {[type]} payId [支付方式ID]
     * @return {[type]}           [{}]
     */
    deliveryData(orderInfo, payId) {
        return this.payApiModel.getResourceData(FRAUD_CONTENT_CODE).then(procData => {
            return Object.assign(orderInfo, this._execOrderData(orderInfo, procData && procData.data || {}, payId));
        });
    }

    pcpayNotify(param) {
        return this.payApiModel.pcpayNotify(
            param.orderCode, param.payId, param.totalFee, param.bankName || '',
            param.bankCode || '', param.tradeNo || '', param.bankBillNo || ''
        );
    }
};