seckill.js 9.25 KB
/**
 *  秒杀结算
 */
'use strict';
const _ = require('lodash');
const crypto = global.yoho.crypto;
const helpers = global.yoho.helpers;
const co = Promise.coroutine;
const userModel = require('../models/user');
const addressModel = require('../models/address');
const seckillModel = require('../models/seckill');
const headerModel = require('../../../doraemon/models/header'); // 头部model
const orderModel = require('../models/order');
const shoppingModel = require('../models/shopping');
const paymentProcess = require(global.utils + '/payment-process');

const BAD_REQUEST = '非法请求';
const SLAT = 'yohobuyseckill98';

exports.ensure = (req, res, next) => {
    const sku = parseInt(req.query.sku, 10);
    const skn = parseInt(req.query.skn, 10);
    const uid = req.user.uid;
    let activityId;

    let orderInfo = req.cookies['order-info'];

    try {
        orderInfo = JSON.parse(req.cookies['order-info']);
    } catch (e) {
        orderInfo = {};
    }

    // require skn, sku;
    if (!(sku && skn)) {
        return next();
    }

    co(function*() {
        let paymentOption = {
            buy_number: 1,
            yoho_coin_mode: 0, // 默认不使用有货币
            product_sku: sku,
            sku_type: 'S',
            uid
        };
        let skillData = yield req.ctx(seckillModel).skillData(skn); // 根据skn查活动信息
        let view = {
            orderEnsure: false,
            message: ''
        };

        skillData = skillData.data;

        // 不在秒杀中
        if (skillData && (skillData.status !== 2)) {
            return res.redirect('/product/seckill');
        }

        if (!(
            skillData &&
                skillData.secKillSku.some(obj => obj.productSku === sku) // skn has sku;
        )) {
            view.message = '挤爆啦,系统繁忙';
            return res.render('order-ensure', Object.assign({
                module: 'cart',
                page: 'seckill',
                width750: true,
                localCss: true,
                pageHeader: headerModel.setNav({
                    navTitle: '确认订单',
                    backUrl: '/product/' + skn + '.html' // 商品url改版
                }),
            }, view));
        }

        paymentOption.activity_id = activityId = skillData.activityId;

        let orderComputerData;
        let limitMessage;

        if (orderInfo) {
            orderComputerData = yield req.ctx(seckillModel).compute(_.assign(paymentOption, {
                delivery_way: orderInfo.deliveryId || 1,
                payment_type: orderInfo.paymentType || 1,
                use_yoho_coin: orderInfo.yohoCoin || 0,
                gift_card_code: orderInfo.gift_card_code || null
            }));

            if (orderComputerData.code === 9999992) {
                limitMessage = '人太多啦,请稍后再试!';
            }
        }

        let [userProfile, address, paymentInfo, validGiftCardCountData] = yield Promise.all([
            req.ctx(userModel).queryProfile(uid),
            req.ctx(addressModel).addressData(uid),
            req.ctx(seckillModel).payment(paymentOption, orderInfo, _.get(orderComputerData, 'data')),
            req.ctx(shoppingModel).countUsableGiftCard(uid) // 可用礼品卡数量
        ]);

        let validGiftCardCount = _.get(validGiftCardCountData, 'data.count', 0);

        // 获取用户完整手机号
        let mobile = _.get(userProfile, 'data.mobile', '');
        let orderAddress = _.get(paymentInfo, 'address', []);
        let addressList = _.get(address, 'data', []);

        orderAddress.length && _.forEach(addressList, address => { //eslint-disable-line
            if (address.address_id === orderAddress.address_id) {
                mobile = address.mobile;
                return false;
            }
        });

        if (paymentInfo.code !== 200) {
            view = {
                orderEnsure: false,
                message: paymentInfo.message
            };

            // hotfix: nginx 接口限流, code:9999991时没message 信息
            if (!view.message) {
                view.message = '挤爆啦,系统繁忙';
            }
        } else {
            // 渲染
            view = _.assign({
                seckill: skillData,
                orderEnsure: true,
                sku,
            }, paymentInfo.data, {
                choseGiftCard: helpers.urlFormat('/cart/index/new/selectGiftcard'),
                giftCards: paymentProcess.handleGiftCards({
                    validGiftCardCount: validGiftCardCount,
                    orderCompute: _.get(orderComputerData, 'data')
                })
            });
        }

        res.locals.title = '确认订单';
        view.limitMessage = limitMessage;
        res.render('order-ensure', Object.assign({
            module: 'cart',
            page: 'seckill',
            pageHeader: headerModel.setNav({
                navTitle: '确认订单',
                backUrl: '/product/' + skn + '.html' // 商品url改版
            }),
            width750: true,
            localCss: true,
            userMobile: mobile,
            cartToken: crypto.encryption(SLAT, [sku, activityId].join(''))
        }, view));
    })().catch(next);
};

exports.compute = (req, res, next) => {
    const uid = req.user.uid,
        sku = req.body.sku,
        paymentType = parseInt(req.body.paymentType || 1, 10),
        activityId = req.body.activityId;

    if (!req.xhr) {
        return next(400);
    }

    // 必填字段
    if ([uid, sku, activityId, paymentType].some(field => !field)) {
        return res.status(400).json({
            code: 400,
            msg: BAD_REQUEST
        });
    }

    const options = {
        sku_type: 'S', // 秒杀
        buy_number: 1,
        yoho_coin_mode: 1,
        payment_type: paymentType,
        uid: req.user.uid,
        product_sku: sku,
        delivery_way: req.body.deliveryId || 1,
        use_yoho_coin: req.body.yohoCoin || 0,
        gift_card_code: req.body.gift_card_code,
        activity_id: activityId
    };

    return req.ctx(seckillModel).compute(options)
        .then(result => {
            res.json(result.data);
        })
        .catch(next);
};

exports.submit = (req, res, next) => {
    const uid = req.user.uid,
        sku = req.body.sku,
        activityId = req.body.activityId,
        deliveryTime = parseInt(req.body.deliveryTime, 10),
        deliveryWay = parseInt(req.body.deliveryWay, 10),
        paymentId = parseInt(req.body.paymentId, 10),
        paymentType = parseInt(req.body.paymentType, 10),
        token = req.body.cartToken;

    let udid = req.sessionID || 'yoho';
    let addressId = req.body.addressId || '';
    let verifyCode = req.body.verifyCode || null;

    if (!req.xhr) {
        return next();
    }

    let compareToken = crypto.encryption(SLAT, [sku, activityId].join(''));

    if (token !== compareToken) {
        return next();
    }

    if (!addressId) {
        return res.json({code: 400, message: '请选择地址'});
    } else {
        addressId = req.body.addressId;
    }

    if ([uid, sku, activityId, addressId, deliveryTime,
        deliveryWay, paymentId, paymentType
    ].some(field => !field)) {
        return res.status(400).json({
            code: 400,
            message: BAD_REQUEST
        });
    }

    const options = {
        sku_type: 'S',
        buy_number: 1,
        use_yoho_coin: parseFloat(req.body.useYohoCoin) || 0,
        remark: req.body.remark || '',
        gift_card_code: req.body.gift_card_code,
        address_id: addressId,
        delivery_time: deliveryTime,
        delivery_way: deliveryWay,
        payment_id: paymentId,
        payment_type: paymentType,
        product_sku: sku,
        activity_id: activityId,
        uid,
        ip: req.ip || '',
        udid: req.sessionID || 'yoho'
    };

    if (req.body.invoice === 'true') {
        let invoicesTitlePersonal = req.body.invoices_title_personal ? req.body.invoices_title_personal : '个人';
        let invoicePayableType = _.parseInt(req.body.invoice_payable_type);

        _.assign(options, {
            invoices_type: 2,
            invoices_type_id: 12,
            invoice_payable_type: invoicePayableType,
            receiverMobile: req.body.receiverMobile || '',
        });

        if (invoicePayableType === 1) {
            // 开个人发票
            options.invoices_title = invoicesTitlePersonal;
        } else {
            // 开公司发票
            options.invoices_title = req.body.invoices_title;
            options.buyerTaxNumber = req.body.buyerTaxNumber;
        }
    }

    co(function* () {
        // 使用礼品卡,发送验证码
        if (options.gift_card_code) {
            if (!verifyCode) {
                yield req.ctx(orderModel).giftCardSendSms(uid);

                return res.json({
                    code: 411
                });
            } else {
                let verifyResult = yield req.ctx(orderModel).validRegCode({
                    uid, verifyCode, udid
                });

                if (verifyResult.code !== 200) {
                    return res.json(verifyResult);
                }
            }
        }
        let result = yield req.ctx(seckillModel).submit(options);

        if (result) {
            res.clearCookie('order-info');
            res.json(result);
        }
    })().catch(next);
};