returns.js 12.6 KB
/**
 *  个人中心 退换货
 *  @author chenxuan <xuan.chen@yoho.cn>
 */

'use strict';

const _ = require('lodash');
const path = require('path');
const Promise = require('bluebird');
const returnAPI = require('./returns-api');

// 使用 product中的分页逻辑
const pagerPath = path.join(global.appRoot, '/apps/product/models/public-handler.js');
const pager = require(pagerPath).handlePagerData;

const co = Promise.coroutine;
const api = global.yoho.API;
const helpers = global.yoho.helpers;

// 常量
const REFUND = 1; // 退货
const EXCHANGE = 2; // 换货
const TRUE = 'Y';
const RETURNS_EMPTY = '您没有退/换货订单';
const REFUND_URI = '/home/returns/refundDetail';
const EXCHANGE_URI = '/home/returns/exchangeDetail';

// 处理退换货商品链接
const getProductUrlBySkc = (pid, gid, cnAlphabet) => {
    cnAlphabet = cnAlphabet || 'cnalphabet';

    return helpers.getUrlBySkc(pid, gid, cnAlphabet);
};

const setDetailGoods = (list) => {
    let resData = [];

    _.forEach(list, value => {
        resData.push({
            name: value.product_name || '',
            reason: value.reason_name
        });
    });

    return resData;
};

// 处理订单商品的数据
function getGoodsData(goods) {
    const arr = [];

    goods.forEach(good => {
        const obj = {};
        const cnAlphabet = good.cn_alphabet || '';

        obj.href = getProductUrlBySkc(good.product_id, good.goods_id, cnAlphabet);
        obj.thumb = helpers.image(good.goods_image, 60, 60);
        obj.name = good.product_name;
        obj.color = good.color_name;
        obj.size = good.size_name;

        arr.push(obj);
    });

    return arr;
}

/**
 * 退换货列表页数据
 * @param  {string} uid   用户 uid
 * @param  {Number} page  当前页数
 * @param  {Number} limit 每页最大条数
 * @return {Object}             Promise
 */
const getReturnsList = co(function*(uid, page, limit) {
    page = Number.parseInt(page, 10) || 1;
    limit = Number.parseInt(limit, 10) || 10;

    const obj = {
        orders: [],
        pager: {}
    };
    let response = yield api.post('', {
        method: 'app.refund.getList',
        data: { uid: uid, page: page, limit: limit }
    });
    let repData = response.data;


    // 处理数据
    if (response.code === 200 && repData && repData.list.length) {
        obj.pager = pager(repData.total, {
            page: page,
            limit: limit
        });

        repData.list.forEach(item => {
            const t = {};

            t.returnId = item.id;
            t.orderNum = item.order_code;
            t.orderTime = item.oreder_create_time.replace('-', '/');
            t.returnTime = item.create_time;
            t.returnStatus = item.status_name;


            const canCancel = item.canCancel === TRUE;
            let isChange, uri;

            switch (item.refund_type) {
                case REFUND:
                    isChange = false;
                    if (canCancel) {
                        uri = REFUND_URI;
                    }
                    break;
                case EXCHANGE:
                    isChange = true;
                    if (canCancel) {
                        uri = EXCHANGE_URI;
                    }
                    break;
                default:
            }

            t.isChange = isChange;
            t.canCancelUrl = helpers.urlFormat(uri);
            t.moreHref = helpers.urlFormat(uri, { id: item.id });
            t.goods = getGoodsData(item.goods);

            obj.orders.push(t);
        });
    } else {
        obj.empty = RETURNS_EMPTY;
    }

    return obj;
});

const getOrderRefund = (orderCode, uid) => {
    let process = function*() {
        let resData = {};
        let result = yield returnAPI.getRefundGoodsAsync(orderCode, uid);

        if (result.data) {
            let goods = [];
            let returnReason = result.data.return_reason,
                remarks = _.split(_.get(result, 'data.special_notice.remark', ''), '   ', 2), // 使用3个空格拆分
                amount = 0;


            _.forEach(_.get(result, 'data.goods_list', []), value => {
                let cnAlphabet = value.cn_alphabet || 'cnalphabet';
                let item = {
                    href: getProductUrlBySkc(value.product_id, value.goods_id, cnAlphabet),
                    name: value.product_name,
                    color: value.color_name,
                    size: value.size_name,
                    price: value.last_price,
                    skn: value.product_skn,
                    skc: value.product_skc,
                    sku: value.product_sku,
                    goods_type_id: value.goods_type_id,
                    goods_type: value.goods_type,
                    reason: returnReason
                };

                amount += parseInt(value.last_price, 10);

                // tar note 为每个特殊商品都添加标识
                if (value.is_limit_skn === 'Y') {
                    item.specialNoticeBo = {
                        title: _.get(result, 'data.special_notice.title', ''),
                        remark1: remarks[0] || '',
                        remark2: remarks[1] || ''
                    };

                    // tar note 对数组做处理,为不显示的添加 inactive
                    if (result.data.special_return_reason) {
                        let spReason = result.data.special_return_reason;

                        _.forEach(item.reason, (subVal, subKey) => { // eslint-disable-line
                            if (_.indexOf(spReason, subKey)) {
                                _.set(item, `reason[${subKey}].inactive`, true);
                            }
                        });
                    }
                }

                goods.push(item);

                // 商品中有鞋类,传给前端标识
                if (value.hasShoes) {
                    _.set(resData, 'tips.footwear', true);
                }
            });

            Object.assign(resData, {
                goods: goods,
                orderCode: orderCode,

                // 计算相关支付细节
                amount: amount - _.get(result, 'data.yoho_coin_num', 0) -
                    _.get(result, 'data.coupon_amount', 0),
                yohoCoin: result.data.yoho_coin_num,
                coupon: result.data.coupon_amount,
                cash: amount
            });

            _.forEach(result.data.return_amount_mode, (val, key) => {
                if (val.is_default === 'Y') {
                    _.set(result, `data.return_amount_mode[${key}].default`, true);
                }
            });

            resData.returnAmountMode = result.data.return_amount_mode;
        }

        return resData;
    };

    return co(process)();
};

const getRefundDetail = (applyId, uid) => {
    let process = function*() {
        let resData = {};
        let result = yield Promise.all([
            returnAPI.getRefundDetailAsync(applyId, uid),
            returnAPI.getExpressCompanyAsync()
        ]);

        if (result[0].data) {
            let data = result[0].data;
            let detail = {
                isChange: false,
                returnId: applyId,
                orderNum: data.source_order_code,
                nowStatus: data.status_name,
                applyTime: data.create_time,
                payMode: data.source_payment_type_desc || '',
                backMode: data.return_amount_mode_name || '',
                goods: setDetailGoods(data.goods_list)
            };

            if (+data.status !== 0) {
                detail.express = {
                    id: _.get(data, 'notice.express_id', ''),
                    company: _.get(data, 'notice.express_company', ''),
                    number: _.get(data, 'notice.express_number', '')
                };
            }

            detail.statusList = [];
            _.forEach(data.statusList, value => {
                detail.statusList.push({
                    name: value.name,
                    act: value.act === 'Y'
                });
            });

            if (data.canCancel === 'Y') {
                detail.canCancelUrl = '/home/refund/cancel';
            }

            resData.detail = detail;

        }

        if (result[1].data && resData.detail) {
            _.set(resData, 'detail.expressList', _.toArray(result[1].data));
        }

        return resData;
    };

    return co(process)();
};

const getOrderExchange = (orderCode, uid) => {
    let process = function*() {
        let resData = {};
        let result = yield returnAPI.getExchangeGoodsAsync(orderCode, uid);

        if (result.data) {
            let goods = [];
            let sknPromise = [];
            let returnReason = result.data.return_reason,
                remarks = _.split(_.get(result, 'data.special_notice.remark', ''), '   ', 2); // 使用3个空格拆分

            _.forEach(_.get(result, 'data.goods_list', []), value => {
                let cnAlphabet = value.cn_alphabet || 'cnalphabet';
                let item = {
                    href: getProductUrlBySkc(value.product_id, value.goods_id, cnAlphabet),
                    thumb: value.goods_image,
                    name: value.product_name,
                    color: value.color_name,
                    size: value.size_name,
                    price: value.last_price,
                    skn: value.product_skn,
                    skc: value.product_skc,
                    sku: value.product_sku,
                    goods_type_id: value.goods_type_id,
                    reason: returnReason
                };

                // tar note 为每个特殊商品都添加标识
                if (value.is_limit_skn === 'Y') {
                    item.specialNoticeBo = {
                        title: _.get(result, 'data.special_notice.title', ''),
                        remark1: remarks[0] || '',
                        remark2: remarks[1] || ''
                    };

                    // tar note 对数组做处理,为不显示的添加 inactive
                    if (result.data.special_return_reason) {
                        let spReason = result.data.special_return_reason;

                        _.forEach(item.reason, (subVal, subKey) => { // eslint-disable-line
                            if (_.indexOf(spReason, subKey)) {
                                _.set(item, `reason[${subKey}].inactive`, true);
                            }
                        });
                    }
                }

                goods.push(item);

                // 商品中有鞋类,传给前端标识
                if (value.hasShoes) {
                    _.set(resData, 'tips.footwear', true);
                }

                sknPromise.push(returnAPI.getProductDataAsync(value.product_skn));
            });

            Object.assign(resData, {
                orderCode: orderCode,

                // 换货地址相关数据(邮编为可空参数)
                name: _.get(result, 'data.address.consignee', ''),
                area: _.get(result, 'data.address.area', ''),
                area_code: _.get(result, 'data.address.area_code', ''),
                address: _.get(result, 'data.address.address', ''),
                phone: _.get(result, 'data.address.mobile', ''),
                postcode: _.get(result, 'data.address.zip_code', '')
            });

            let product = yield Promise.all(sknPromise);

            _.forEach(product, (value, key) => { // 遍历得到每件商品
                let colorSize = [];

                _.forEach(value.goods_list, val => { // 遍历商品得到每个颜色
                    let size = [];

                    _.forEach(val.size_list, v => { // 遍历颜色得到每个尺码
                        if (+v.storage_number > 0) { // 当某个尺码下有库存时,将该颜色及其对应的尺码加入该商品选项下
                            size.push(v);
                        }
                    });

                    if (size.length) {
                        colorSize.push({
                            color: val.color_name,
                            colorId: val.color_id,
                            goodsId: val.goods_id,
                            sizeList: size
                        });
                    }
                });

                if (colorSize.length) {
                    goods[key].colorSize = colorSize;
                } else {
                    goods[key].banMsg = '库存不足不能换货';
                }

            });

            resData.goods = goods;
        }

        return resData;
    };

    return co(process)();
};

module.exports = {
    getReturnsList,
    getOrderRefund,
    getRefundDetail,
    getOrderExchange
};