'use strict'; const { CrudService } = require('naf-framework-mongoose-free/lib/service'); const { BusinessError, ErrorCode } = require('naf-core').Error; const _ = require('lodash'); const assert = require('assert'); // class TradeService extends CrudService { constructor(ctx) { super(ctx, 'trade'); this.redis = this.app.redis; this.redisKey = this.app.config.redisKey; this.redisTimeout = this.app.config.redisTimeout; this.shopModel = this.ctx.model.Shop.Shop; this.goodsModel = this.ctx.model.Shop.Goods; this.goodsSpecModel = this.ctx.model.Shop.GoodsSpec; this.cartModel = this.ctx.model.Trade.Cart; this.setModel = this.ctx.model.Shop.GoodsSet; } /** * 检查选中的购物车是否符合购买的条件 * @param {Object} body 请求体 * @param body.cartIds 选中的购物车id列表 * @param {Boolean} makeCache 生成缓存 */ async checkCartBuy({ cartIds }, makeCache = true) { const list = await this.cartModel.find({ _id: cartIds }); let result = { result: true }; for (const i of list) { const res = await this.checkCanBuy(i, false); if (res.result !== true) { result = res; break; } } if (makeCache) { const key = await this.makeOrderKey(cartIds); result.key = key; } return result; } /** * 检测是否可以购买该物品 * @param {Object} data 查询条件 * @param param.shop 商店id * @param param.goods 商品id * @param param.goodsSpec 商品规格id * @param param.num 购买数量 * @param param.type 订单类型: 0:常规单 1:团购单,需要按团购价计算 * @param param.group 团id * @param param.inviter 邀请用户id 返现部分 * @param param.is_set 是否是套装,默认 1 不是套装 * @param params.set_id 套装id * @param makeCache 生成缓存 */ async checkCanBuy(data, makeCache = true) { if (!_.isArray(data)) data = [ data ]; let result = { result: true }; for (const i of data) { const { is_set = '1' } = i; if (is_set === '1') { // 非套装,使用正常的判断 result = await this.checkGoodsCanBuy(i); } else { // 套装,使用套装判断 result = await this.checkSetCanBuy(i); } if (result.result !== true) break; } // #endregion if (result.result && makeCache) { const key = await this.makeOrderKey(data); result.key = key; } return result; } /** * 套装判断是否可以购买 * @param {Object} data 购物车/直接购买 数据对象 */ async checkSetCanBuy(data) { const { num, shop } = data; // 取set_id是在购物车检查是否可以购买; data._id是下单时使用 // 已经将购物车那边的数据加上了set_id,不过先这么写,兼容 const set_id = _.get(data, 'set_id', data._id); let result = { result: true }; if (!shop) { result.result = false; result.msg = '缺少店铺信息'; return result; } // 1.检查商店是否正常运行 const shopData = await this.shopModel.findById(shop); const shopRes = this.checkShop(shopData); if (shopRes.result !== true) { result = shopRes; return result; } const setData = await this.setModel.findById(set_id).lean(); const { set, is_use } = setData; if (is_use === '1') return { result: false, msg: '套装已下架' }; for (const sd of set) { const { goods, spec, set_num } = sd; if (!goods) { result.result = false; result.msg = '缺少商品信息'; break; } if (!spec) { result.result = false; result.msg = '缺少商品规格信息'; break; } if (!num) { result.result = false; result.msg = '缺少购买数量'; break; } // 2.检查商品是否可以购买 const goodsData = await this.goodsModel.findById(goods); const goodsRes = this.checkGoods(goodsData); if (goodsRes.result !== true) { result = goodsRes; break; } // 3.根据套装库存设置判断是走各个商品库存还是走套装库存 // 走各个商品库存 const goodsSpecData = await this.goodsSpecModel.findById(spec); // 单独计算下商品数量 = 购买数量 * 组成套装的数量 const setGoodsNum = this.ctx.multiply(num, set_num); const gsRes = this.checkGoodsSpec(goodsSpecData, setGoodsNum, '0'); if (gsRes.result !== true) { result = gsRes; break; } } return result; } /** * 常规商品判断是否可以购买 * @param {Object} data 购物车/直接购买 数据对象 */ async checkGoodsCanBuy(data) { let result = { result: true }; const { shop, goods, goodsSpec, num } = data; if (!shop) { result.result = false; result.msg = '缺少店铺信息'; return result; } if (!goods) { result.result = false; result.msg = '缺少商品信息'; return result; } if (!goodsSpec) { result.result = false; result.msg = '缺少商品规格信息'; return result; } if (!num) { result.result = false; result.msg = '缺少购买数量'; return result; } // 1.检查商店是否正常运行 const shopData = await this.shopModel.findById(shop); const shopRes = this.checkShop(shopData); if (shopRes.result !== true) { result = shopRes; return result; } // 2.检查商品是否可以购买 const goodsData = await this.goodsModel.findById(goods); const goodsRes = this.checkGoods(goodsData); if (goodsRes.result !== true) { result = goodsRes; return result; } // 3.检验该规格是否可以购买 const goodsSpecData = await this.goodsSpecModel.findById(goodsSpec); const gsRes = this.checkGoodsSpec(goodsSpecData, num); if (gsRes.result !== true) { result = gsRes; return result; } return result; } /** * 检查商店是否满足条件 * @param {Object} shopData 店铺数据 */ checkShop(shopData) { const result = { result: true }; if (!shopData) { result.msg = '未找到店铺'; result.result = false; return result; } if (shopData.status !== '1') { result.msg = '店铺不处于营业状态'; result.result = false; return result; } return result; } /** * 检查商品是否满足条件 * @param {Object} goodsData 商品数据 */ checkGoods(goodsData) { const result = { result: true }; if (!goodsData) { result.msg = '未找到商品'; result.result = false; return result; } if (goodsData.status === '0') { result.msg = '该商品已下架'; result.result = false; return result; } return result; } /** * 检查商品的规格是否满足购买条件 * @param {Object} goodsSpecData 商品规格的数据 * @param {Number} num 购买数量 * @param {String} is_set 是否是套装;套装不需要检查购买限制 */ checkGoodsSpec(goodsSpecData, num, is_set = '1') { const result = { result: true }; if (!goodsSpecData) { result.msg = '未找到商品的指定规格'; result.result = false; return result; } if (goodsSpecData.status !== '0') { result.msg = '该规格的商品已下架'; result.result = false; return result; } if (goodsSpecData.num < num) { result.msg = '库存量不足'; result.result = false; return result; } if (is_set !== '1') return result; // 判断是否有购买限制 if (_.get(goodsSpecData, 'buy_limit', '0') !== '0') { // 有购买限制,需要检测购买限制 const buy_limit = _.get(goodsSpecData, 'buy_limit'); const limit_num = _.get(goodsSpecData, 'limit_num', 0); if (buy_limit === '1') { if (num < limit_num) { result.msg = `该规格至少购买 ${limit_num} 份, 购买数量不足`; result.result = false; return result; } } else if (buy_limit === '2') { if (num > limit_num) { result.msg = `该规格至多购买 ${limit_num} 份, 购买数量超过上限`; result.result = false; return result; } } else if (buy_limit === '3') { if (num !== limit_num) { result.msg = `该规格只能购买 ${limit_num} 份`; result.result = false; return result; } } } return result; } // 随机字符串产生函数 createNonceStr() { return Math.random().toString(36).substr(2, 15); } // 生成key async makeOrderKey(data) { const str = this.createNonceStr(); const key = `${this.redisKey.orderKeyPrefix}${str}`; const value = JSON.stringify(data); await this.redis.set(key, value, 'EX', this.redisTimeout); return str; } } module.exports = TradeService;