'use strict'; const Promise = require('bluebird'); const co = Promise.coroutine; const _ = require('lodash'); const moment = require('moment'); const helpers = global.yoho.helpers; const pager = require('./pager').handlePagerData; const OrderApi = require('./orders-api'); const ChannelConfig = require('./channel-config'); module.exports = class extends global.yoho.BaseModel { constructor(ctx) { super(ctx); this.ORDER_TYPE = { all: 1, // 全部 waitingForPay: 2, // 待付款 waitingForSend: 3, // 待发货 waitingForReceive: 4, // 待收货 completed: 5, // 已完成 canceled: 7 // 已取取消 }; this.ORDER_EMPTY_DESC = { 1: '您还没有任何订单', 5: '您目前还没有成功的订单', 7: '您还没有任何取消的订单' }; this.TABS = [ {type: 1, name: '现有订单'}, {type: 5, name: '成功订单'}, {type: 7, name: '已取消订单'} ]; this.ORDER_OP_ALL = [ { type: 'closeOrder', name: '取消订单', cancelOrder: true, hrefFun: () => 'javascript:void(0)' // eslint-disable-line }, { type: 'buyNow', name: '立即付款', payNow: true, hrefFun: it => helpers.urlFormat('/shopping/newpay', {ordercode: it}) }, { type: 'getExpress', name: '查看物流', express: true, hrefFun: () => 'javascript:void(0)' // eslint-disable-line }, { type: 'confirm', name: '确认订单', confirmReceived: true, hrefFun: () => 'javascript:void(0)' // eslint-disable-line }, { type: 'delOrder', name: '删除订单', delOrder: true, hrefFun: () => '' }, { type: 'lookQrcode', name: '查看二维码', qrcode: true, hrefFun: it => helpers.urlFormat('/home/qrcode', {orderCode: it}) }, { type: 'afterService', name: '售后服务', afterService: true, hrefFun: () => '' }, { type: 'exchange', name: '申请换货', optDis: true, hrefFun: it => helpers.urlFormat('/home/returns/exchangerequest', {orderCode: it}) }, { type: 'refund', name: '申请退货', optDis: true, hrefFun: it => helpers.urlFormat('/home/returns/refundrequest', {orderCode: it}) }, { type: 'shareOrder', name: '晒单评价', comment: true, hrefFun: it => helpers.urlFormat('/home/comment/order', {orderId: it}) }, { type: 'readd', name: '再次购买', reBuy: true, hrefFun: () => '' }, { type: 'showDetail', name: '查看订单', showDetail: true, hrefFun: it => helpers.urlFormat('/home/orders/detail', {orderCode: it}) }, { type: 'refundApply', name: '申请退款', refund: true, hrefFun: () => 'javascript:void(0)' // eslint-disable-line }, { type: 'deposit', name: '定金预售商品只能在APP端操作', deposit: true, hrefFun: () => '' } ]; } /** * 转换价格 * * @param float|string $price 价格 * @return float|string 转换之后的价格 */ transPrice(price) { return price ? (price * 1).toFixed(2) : '0.00'; } _getTabs(type) { type = type || 1; return this.TABS.map((tab) => { tab.active = tab.type === type; tab.url = helpers.urlFormat('/home/orders', {page: 1, type: tab.type}); return tab; }); } _getOrderStatus(isCancel, status, payType, payStatus, statusStr) { // 初始化:未取消,待付款 let ret = { cancel: false, keyName: 'noPay' }; if (isCancel === 'Y') { ret = {cancel: true, statusStr: '已取消'}; } else { switch (status) { case 0: // '订单已成功,等待付款' if (payType !== 2 && payStatus === 'N') { ret.keyName = 'noPay'; } else if (payType !== 2 && payStatus === 'Y') { // '订单已付款,等待备货中' ret.keyName = 'paid'; } else if (payType === 2 && payStatus === 'N') { // '订单已成功,等待备货中'-货到付款 ret.keyName = 'complete'; } break; case 1: case 2: case 3: // '订单已付款,等待备货中' ret.keyName = 'paid'; break; case 4: case 5: // '订单已发货' ret.keyName = 'shipped'; break; case 6: // '交易完成'; ret.keyName = 'reback'; break; default: ret.keyName = 'unknown'; } } ret.statusStr = statusStr; return ret; } _getOperateInfo(orderCode, operators) { return _.flatten(operators.map(it => this.ORDER_OP_ALL.filter(op => op.type === it).map((op) => { return Object.assign({}, op, { href: op.hrefFun(orderCode) }); }))); } _getGoodsTag(attribute, goodsType) { let goodsTagName = ''; switch (goodsType) { // 赠品 case 'gift': goodsTagName = 'freebie'; break; // 加价购 case 'price_gift': goodsTagName = 'advanceBuy'; break; // 预售 case 'advance': goodsTagName = 'preSaleGood'; break; // outlet case 'outlet': goodsTagName = ''; break; // 免单 case 'free': goodsTagName = ''; break; // 电子 case 'ticket': goodsTagName = 'virtualGood'; break; default: break; } // 虚拟 if (attribute === 3) { goodsTagName = 'virtualGood'; } return goodsTagName; } _getUrlSafe(url) { if (!url) { return ''; } const WhiteList = ['/special_', '/special/']; if (_.some(WhiteList, (val) => _.includes(url, val))) { return url; } return url.replace('http://', '//'); } _getExpressInfo(orderCode, uid, paymentType, createTime, isDetail) { let that = this; return co(function * () { let result = {}; isDetail = isDetail || false; result.logisticsUrl = ''; result.logisticsImg = ''; result.logisticsCompany = ''; result.courierNumbe = ''; result.logistics = []; if (paymentType === 1) { if (isDetail) { result.logistics.push(''); } else { result.logistics.push(moment.unix(createTime).format('YYYY.MM.DD HH:mm:ss') + ' 您的订单已提交,等待付款'); } } if (paymentType === 2) { if (isDetail) { result.logistics = result.logistics.concat([ moment.unix(createTime).format('YYYY-M-D H:m:s'), ' ', '您的订单已提交,等待审核' ]); } else { result.logistics.push(moment.unix(createTime).format('YYYY.MM.DD HH:mm:ss') + ' 您的订单已提交,等待审核'); } } // 有物流 if (orderCode) { let logistics = yield new OrderApi(that.ctx).getLogisticsData(orderCode, uid); if (_.has(logistics, 'data')) { result.logisticsUrl = that._getUrlSafe(logistics.data.url); result.logisticsImg = logistics.data.logo || ''; result.logisticsCompany = logistics.data.caption || ''; result.courierNumbe = logistics.data.express_number || ''; let expressDetail = logistics.data.express_detail || []; if (!_.isEmpty(expressDetail)) { let logisticsTmp = result.logistics[0]; // 暂存 result.logistics = []; expressDetail.forEach((value) => { let pos = value.accept_address.indexOf(' '); pos = pos === -1 ? 0 : pos; let city = value.accept_address.substr(0, pos); let exInfo = value.accept_address.substr(pos); if (isDetail) { result.logistics.push([value.acceptTime, city, exInfo]); } else { result.logistics.push(value.acceptTime + city + exInfo); } }); // 把最初的处理放最后 result.logistics.push(logisticsTmp); } } } return result; })(); } /** * 获取我的订单列表数据 */ getOrders(uid, page, limit, type, isPage) { let that = this; return co(function *() { isPage = isPage || false; let orderInfo = yield new OrderApi(that.ctx).getUserOrders( uid, page, limit, type ).then(res => _.get(res, 'data', {})); if (_.isEmpty(_.get(orderInfo, 'order_list', []))) { return { empty: that.ORDER_EMPTY_DESC[type] || '', list: [] }; } let result = {}; const handleOrder = function(order) { order.payment_type = +order.payment_type; let newOrder = {}; newOrder.orderNum = order.order_code; // 订单标识 newOrder.orderTime = moment.unix(_.get(order, 'create_time')).format('YYYY-MM-DD HH:mm:ss'); newOrder.time = _.get(order, 'create_time'); newOrder.payType = _.get(order, 'payment_type'); newOrder.title = _.get(order, 'order_title'); if (order.is_cancel === 'Y' || order.status === 6) { newOrder.canDelete = true; // 删除订单 } let statusInfo = that._getOrderStatus(order.is_cancel, order.status, order.payment_type, order.payment_status, order.status_str ); // 订单状态 if (statusInfo.cancel) { newOrder.cancel = statusInfo.cancel; } else { if (statusInfo.keyName) { newOrder[statusInfo.keyName] = true; } } newOrder.statusStr = statusInfo.statusStr; newOrder.goods = _.get(order, 'order_goods', []).map((good) => { let newGood = {}; newGood.href = helpers.getUrlBySkc(good.product_skn); newGood.thumb = helpers.image(good.goods_image, 100, 100); newGood.name = good.product_name; newGood.color = good.factory_color_name; newGood.size = good.size_name; newGood.price = that.transPrice(good.sales_price);// 默认显示销售价 newGood.isVipPrice = good.discount_tag === 'V'; newGood.isStuPrice = good.discount_tag === 'S'; // 划线的价格 if (+good.real_pay_price < +good.sales_price) { newGood.price = that.transPrice(good.real_pay_price);// 显示分摊价 newGood.linePrice = that.transPrice(good.sales_price); // 划线的价格 } // 赠品、加价购 if (good.goods_type === 'gift' || good.goods_type === 'price_gift') { newGood.price = that.transPrice(good.goods_price);// 显示成交价 newGood.linePrice = that.transPrice(good.sales_price); // 划线的价格 } let buyNum = _.parseInt(good.buy_number); let refundNum = _.parseInt(good.refund_num); newGood.count = buyNum; newGood.refundStatus = refundNum > 0;// 只要发生一件退换,退换过的标记 newGood.goRefundUrl = helpers.urlFormat('/home/returns'); newGood.arrivalDate = good.expect_arrival_time; let goodsTagName = that._getGoodsTag(+order.attribute, good.goods_type); if (goodsTagName) { newGood[goodsTagName] = true; } return newGood; }); newOrder.pay = order.amount; // 付款数 newOrder.fregit = order.shipping_cost; // 邮费 // 操作 let op = _.get(order, 'links', []); // 新增加一些操作 op.unshift('showDetail'); if (_.get(order, 'is_support_exchange', 'N') === 'Y') { op.push('exchange'); } if (_.get(order, 'is_support_refund', 'N') === 'Y') { op.push('refund'); } if (+order.attribute === 9 || +order.attribute === 11) { op = ['deposit']; } newOrder.operation = that._getOperateInfo(order.order_code, op); return newOrder; }; result.list = _.get(orderInfo, 'order_list', []).map(handleOrder); if (isPage) { result.pager = { total: orderInfo.total, pageTotal: orderInfo.page_total, page: orderInfo.page }; } return result; })(); } index(uid, page, limit, type) { let that = this; return co(function * () { let result = yield Promise.props({ orders: that.getOrders(uid, page, limit, type, true), cancelReason: new OrderApi(that.ctx).closeReasons().then(res => _.get(res, 'data', '')) }); result.pager = pager(_.get(result, 'orders.pager.total', 0), {page, limit, type}); return Object.assign(result, { tabs: that._getTabs(type) }); })(); } reBuy(...params) { let that = this; return co(function * () { let newOrder = yield new OrderApi(that.ctx).reBuy(...params); if (newOrder.code !== 200) { return { code: 400, message: '商品加入购物车失败' }; } return { code: 200, message: '商品已重新加入购物车', data: newOrder.data }; })(); } del(...params) { return new OrderApi(this.ctx).del(...params).then(orderInfo => { if (!_.has(orderInfo, 'code')) { return { code: 400, message: '删除失败' }; } return orderInfo; }); } _getVirtualPro(isCancel, status, createTime) { let progress = { middleStatus: [ { name: '1. 提交订单', date: moment.unix(createTime).format('YYYY.MM.DD HH:mm:ss') }, { name: '2. 已发货' }, { name: '3. 交易完成' } ] }; if (isCancel === 'N') { if (status === 0) { progress.percent = '30%'; progress.middleStatus[0].cur = true; } else if (status > 0 && status < 6) { progress.percent = '80%'; progress.middleStatus[1].cur = true; } else if (status === 6) { progress.percent = '100%'; progress.middleStatus[2].cur = true; } } return progress; } _getNormalPro(isCancel, status, createTime) { let progress = { middleStatus: [ { name: '1. 提交订单', date: moment.unix(createTime).format('YYYY.MM.DD HH:mm:ss') }, { name: '2. 商品出库' }, { name: '3. 等待收货' }, { name: '4. 交易完成' } ] }; if (isCancel === 'N') { if (status === 0) { progress.percent = '25%'; progress.middleStatus[0].cur = true; } else if (status > 0 && status < 4) { progress.percent = '50%'; progress.middleStatus[1].cur = true; } else if (status >= 4 && status < 6) { progress.percent = '75%'; progress.middleStatus[2].cur = true; } else if (status === 6) { progress.percent = '100%'; progress.middleStatus[3].cur = true; } } return progress; } _getOfflineBySelf(isCancel, status, createTime) { let progress = { middleStatus: [ { name: '1. 提交订单', date: moment.unix(createTime).format('YYYY.MM.DD HH:mm:ss') }, { name: '2. 交易完成' } ] }; if (isCancel === 'N') { if (status === 0) { progress.percent = '50%'; progress.middleStatus[0].cur = true; } else if (status === 6) { progress.percent = '100%'; progress.middleStatus[1].cur = true; } } return progress; } _getOrderDetailOp(orderId, payment, status, isCancel, paymentStatus, paymentType, orderType, attribute, refundStatus, links) { let operation = {}; if (attribute === 9 || attribute === 11) { Object.assign(operation, { deposit: true }); return operation; } // 立刻付款 if (_.includes(links, 'buyNow')) { Object.assign(operation, { goPay: helpers.urlFormat('/shopping/newpay', {ordercode: orderId}) }); } // 取消订单 if (_.includes(links, 'closeOrder')) { Object.assign(operation, { cancelOrder: true }); } // 订单已支付 if (paymentType === 1 && paymentStatus === 'Y' && status < 6) { Object.assign(operation, { paid: true }); } // 确认收货 if (status >= 4 && status < 6 && refundStatus === 0 && attribute !== 3 && isCancel === 'N') { Object.assign(operation, { shipped: true }); } // 订单已取消 if (isCancel === 'Y') { Object.assign(operation, { cancel: true }); } // 虚拟查看二维码 if (attribute === 3) { Object.assign(operation, { checkQrCode: helpers.urlFormat('/home/orders/ticket', {orderCode: orderId}) }); } return operation; } _getPackageInfo(cartInfo) { // 是否拆单 if (cartInfo.is_multi_package !== 'Y') { return []; } return _.get(cartInfo, 'package_list', []).map((pack) => { let newPack = { supplierId: pack.supplier_id, fee: pack.shopping_cost === '0.00' ? '' : pack.shopping_cost, orign: pack.shopping_orig_cost, count: pack.shopping_cut_cost }; newPack.goodlist = _.get(pack, 'goods_list', []).map((good) => { let tagInfo = ChannelConfig.orderTagArr[good.goods_type] || ''; return { src: helpers.image(good.goods_images, 90, 90), goodsType: tagInfo.name || '', classname: tagInfo.classname || '', link: 'javascritp:void(0)' }; }); return newPack; }); } isOfflineBySelf(orderDetail) { return orderDetail.is_offlineshops === 'Y' && orderDetail.is_delivery_offline === 'Y'; } _getOrderDetail(uid, orderId) { let that = this; return co(function * () { let orderInfo = yield new OrderApi(that.ctx).getOrderDetail(uid, orderId); let detail = {}; if (orderInfo.code === 400) { return orderInfo; } if (orderInfo.data) { let orderDetail = orderInfo.data; orderDetail.payment_type = +orderDetail.payment_type; detail.orderNum = orderDetail.order_code; // 订单状态 let statusInfo = that._getOrderStatus( orderDetail.is_cancel, +orderDetail.status, orderDetail.payment_type, orderDetail.payment_status, orderDetail.status_str ); detail.statusStr = statusInfo.statusStr; // 订单是否已完成 detail.complete = +orderDetail.status === 6; detail.progress = statusInfo.cancel ? false : (function() { // 未取消订单,进度 if (+orderDetail.attribute === 3) { return that._getVirtualPro(orderDetail.is_cancel, +orderDetail.status, orderDetail.create_time); } else { if (that.isOfflineBySelf(orderDetail)) { return that._getOfflineBySelf( orderDetail.is_cancel, +orderDetail.status, orderDetail.create_time ); } return that._getNormalPro(orderDetail.is_cancel, +orderDetail.status, orderDetail.create_time); } }()); // 物流信息 detail.traceOrder = {}; detail.traceOrder.orderDate = moment.unix(orderDetail.create_time).format('YYYY.MM.DD HH:mm:ss'); let expressInfo = yield that._getExpressInfo( orderId, uid, +orderDetail.payment_type, orderDetail.create_time, true ); detail.traceOrder.logistics = expressInfo.logistics; if (_.get(expressInfo, 'logistics[0]')) { detail.hastrace = true; } else { detail.hastrace = false; } detail.traceOrder.logisticsCompany = expressInfo.logisticsCompany; detail.traceOrder.courierNumbe = expressInfo.courierNumbe; // 虚拟商品 if (+orderDetail.attribute === 3) { detail.virtualGood = true; detail.virtualPayMode = { payMode: ChannelConfig.payType[orderDetail.payment_type], phone: _.fill(orderDetail.mobile.split(''), '*', 3, 4).join('') }; } else { detail.virtualGood = false; detail.noramlPayMode = { payMode: ChannelConfig.payType[orderDetail.payment_type], payWay: orderDetail.payment_name, deliverTime: orderDetail.delivery_time || '' }; // 配送信息 detail.orderInfo = { receiver: orderDetail.user_name, address: orderDetail.area + orderDetail.address, phone: _.fill(orderDetail.mobile.split(''), '*', 3, 4).join('') + (orderDetail.phone ? ',' + _.fill(orderDetail.phone.split(''), '*', 3, 5).join('') : '') }; if (_.get(orderDetail, 'is_offlineshops') === 'Y') { if (_.get(orderDetail, 'is_delivery_offline') === 'Y') { detail.orderInfo.offlineBySelf = true; detail.offlineBySelf = true; // 进度条的处理 } else { detail.orderInfo.offlineByExpress = true; } detail.offline = true; detail.orderInfo.offlineStore = _.get(orderDetail, 'offline_store', ''); } else { detail.orderInfo.normal = true; } detail.editInfo = { userName: orderDetail.user_name, address: orderDetail.address, areaCode: orderDetail.area_code, mobile: orderDetail.mobile, phoneNum: _.nth(_.split(orderDetail.phone), 0) || '', phoneCode: _.nth(_.split(orderDetail.phone), 1) || '' }; } // 商品信息 if (orderDetail.order_goods) { detail.goods = _.get(orderDetail, 'order_goods', []).map((good) => { let newGood = { url: helpers.getUrlBySkc(good.product_skn), img: helpers.image(good.goods_image, 60, 60), name: good.product_name, color: good.factory_color_name, size: good.size_name, price: that.transPrice(good.sales_price), // 默认显示销售价 isVipPrice: good.discount_tag === 'V', isStuPrice: good.discount_tag === 'S', coin: good.yoho_give_coin, num: good.buy_number, sum: good.goods_amount, sku: good.product_sku, [that._getGoodsTag(+orderDetail.attribute, good.goods_type)]: true }; // 划线的价格 if (+good.real_pay_price < +good.sales_price) { newGood.price = that.transPrice(good.real_pay_price);// 显示分摊价 newGood.linePrice = that.transPrice(good.sales_price); // 划线的价格 } // 赠品、加价购 if (good.goods_type === 'gift' || good.goods_type === 'price_gift') { newGood.price = that.transPrice(good.goods_price);// 显示成交价 newGood.linePrice = that.transPrice(good.sales_price); // 划线的价格 } return newGood; }); } // 详情页-订单付费详情 if (orderDetail.promotion_formulas) { detail.orderBalance = _.get(orderDetail, 'promotion_formulas', []).map((promotion) => { return { promotion: promotion.promotion, account: promotion.promotion_amount }; }); detail.orderBalance.push({ promotion: '实际应支付', account: orderDetail.amount }); } // 发票 if (orderDetail.invoice) { detail.invoiceMode = true; detail.invoiceType = (+_.get(orderDetail, 'invoice.type', 0)) === 2 ? '电子发票' : '纸质发票'; detail.showInvoice = _.get(orderDetail, 'invoice.showInvoice'); detail.pdfUrl = detail.showInvoice ? _.get(orderDetail, 'invoice.pdfUrl') : ''; detail.title = _.get(orderDetail, 'invoice.title') || ''; detail.contentValue = _.get(orderDetail, 'invoice.contentValue') || '个人'; } detail.totalYoho = orderDetail.yoho_give_coin; detail.yohoCoinUrl = helpers.urlFormat('/help/detail', {id: 105}); // 有货币介绍 detail.remark = orderDetail.remark; detail.operation = that._getOrderDetailOp( orderDetail.order_code, +orderDetail.payment, +orderDetail.status, orderDetail.is_cancel, orderDetail.payment_status, orderDetail.payment_type, +orderDetail.order_type, +orderDetail.attribute, +orderDetail.refund_status, orderDetail.links ); detail.packageTitle = orderDetail.package_title; detail.packages = that._getPackageInfo(orderDetail); if (+orderDetail.attribute === 9 || +orderDetail.attribute === 11) { // 定金预售不能操作 } else { // 判断是否可以修改地址 if (orderDetail.can_update_delivery_address === 'Y') { detail.changeable = true; } // 判断是否可以修改省份 if (orderDetail.is_support_change_province === 'N') { detail.changeProvince = true; } } return detail; } })(); } closeReason() { return new OrderApi(this.ctx).closeReasons().then((result) => { return _.get(result, 'data', []); }); } refundReason() { return new OrderApi(this.ctx).refundReason().then((result) => { return _.get(result, 'data', []); }); } detail(uid, orderId) { let that = this; return co(function * () { let apiData = yield Promise.props({ detailData: that._getOrderDetail(uid, orderId), reason: that.closeReason() }); if (apiData.detailData.code === 400) { return {}; } return { detail: apiData.detailData, package: apiData.detailData.package, cancelReason: apiData.reason }; })(); } updateDeliveryAddress(...params) { return new OrderApi(this.ctx).updateDeliveryAddress(...params); } confirm(...params) { return new OrderApi(this.ctx).confirmUserOrder(...params); } cancel(...params) { return new OrderApi(this.ctx).cancelUserOrder(...params); } refund(...params) { return new OrderApi(this.ctx).refund(...params); } express(orderCode, uid, paymentType, createTime) { return this._getExpressInfo(orderCode, uid, paymentType, createTime, true); } };