123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195 |
- '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');
- const { ObjectId } = require('mongoose').Types;
- //
- class CartService extends CrudService {
- constructor(ctx) {
- super(ctx, 'cart');
- this.model = this.ctx.model.Trade.Cart;
- this.goodsSpecModel = this.ctx.model.Shop.GoodsSpec;
- this.platformActModel = this.ctx.model.System.PlatformAct;
- this.gjaModel = this.ctx.model.Shop.GoodsJoinAct;
- this.setModel = this.ctx.model.Shop.GoodsSet;
- this.shopModel = this.ctx.model.Shop.Shop;
- this.goodsModel = this.ctx.model.Shop.Goods;
- }
- /**
- * 返回购物车需要的数据格式
- ** 添加促销部分:
- ** 买赠,特价,加价购: 需要查询每个商品是否参与了这三项活动,需要给出对应数据
- ** 满减/折:不需要在购物车出现
- ** 套装:最后下单时组合,购物车中不需要额外修改
- * @param {Object} query 查询条件
- * @param query.customer 顾客id
- * @return {Array}
- */
- async selfCart({ customer }) {
- assert(customer, '缺少顾客信息');
- let data = await this.model.find({ customer });
- if (data.length > 0) {
- data = JSON.parse(JSON.stringify(data));
- data = data.map(i => ({ ...i, cart_id: i._id }));
- }
- data = await this.getCartGoodsAct(data);
- const actList = await this.ctx.service.trade.order.getActList(data);
- const pageData = await this.ctx.service.trade.order.getPageData(data, actList);
- return pageData;
- }
- /**
- * 实时获取购物车内的商品参与的活动
- * @param {Array} data 购物车商品
- */
- async getCartGoodsAct(data) {
- data = data.map(i => ({ ...i, act: [] }));
- // 实时匹配活动问题
- const platformActList = await this.platformActModel.find({ is_use: '0' });
- const platform_act = platformActList.map(i => ObjectId(i._id).toString());
- for (const cart of data) {
- const { goodsSpec: spec_id, goods: goods_id, act = [], is_set = '1', set_id } = cart;
- if (is_set === '1' || !set_id) {
- // 非套装处理, 套装不参与其他活动
- const gjaList = await this.gjaModel.find({ platform_act, 'goods._id': ObjectId(goods_id).toString(), 'spec._id': ObjectId(spec_id).toString() });
- for (const gja of gjaList) {
- const { platform_act_type: type, platform_act } = gja;
- // 加价购需要额外判断是否是基础商品
- if (type === '4') {
- const goods_type = _.get(gja, 'config.goods_type');
- if (goods_type === 'basic') act.push(platform_act);
- } else act.push(platform_act);
- }
- cart.act = _.uniq(act);
- }
- }
- return data;
- }
- /**
- ** 创建购物车信息,若找到该店的该商品规格.进行库存校验
- ** 数量进行合并;
- ** 反之创建
- ** 添加促销活动部分:
- ** 买赠,特价,加价购: 不需要在创建时处理,而是在查询时实时处理,显示相关信息
- ** 满减/折:不需要在购物车出现
- ** 套装:只有套装需要记录在购物车中,以同一商品形式出现
- * @param {Object} body 请求参数
- * @param body.num 数量
- */
- async create({ num, ...body }) {
- const { customer, shop, goods, goodsSpec, is_set = '1', set_id } = body;
- assert(customer, '缺少顾客信息');
- if (is_set === '1') {
- assert(shop, '缺少店铺信息');
- assert(goods, '缺少商品信息');
- assert(goodsSpec, '缺少商品规格信息');
- } else assert(set_id, '缺少套装id');
- if (is_set === '1') {
- // 非套装 添加购物车
- const query = _.pick(body, [ 'customer', 'shop', 'goods', 'goodsSpec' ]);
- const data = await this.model.findOne(query);
- if (data) {
- const buyNum = this.ctx.plus(data.num, num);
- const { enough, msg } = await this.checkGoodsNum({ goodsSpecId: goodsSpec, num: buyNum });
- if (!enough) throw new BusinessError(ErrorCode.SERVICE_FAULT, msg);
- data.num = buyNum;
- await data.save();
- } else {
- const { enough, msg } = await this.checkGoodsNum({ goodsSpecId: goodsSpec, num });
- if (!enough) throw new BusinessError(ErrorCode.SERVICE_FAULT, msg);
- await this.model.create({ num, ...body });
- }
- } else {
- // 套装添加购物车
- const query = _.pick(body, [ 'customer', 'set_id' ]);
- const data = await this.model.findOne(query);
- if (data) {
- // 计算套装购买数量
- const buyNum = this.ctx.plus(data.num, num);
- const { enough, msg } = await this.checkSetGoodsNum(data, buyNum);
- if (!enough) throw new BusinessError(ErrorCode.SERVICE_FAULT, msg);
- data.num = buyNum;
- await data.save();
- } else {
- const { enough, msg, shop } = await this.checkSetGoodsNum(body, num);
- if (!enough) throw new BusinessError(ErrorCode.SERVICE_FAULT, msg);
- await this.model.create({ shop, num, ...body });
- }
- }
- }
- /**
- * 检查套装购物车库存是否足够
- * @param {Object} data 套装的购物车数据
- * @param {Number} buyNum 套装购买数量
- */
- async checkSetGoodsNum(data, buyNum) {
- const { set_id } = data;
- const setData = await this.setModel.findById(set_id).lean();
- const { shop } = setData;
- const shopData = await this.shopModel.findById(shop);
- const shopRes = this.ctx.service.util.trade.checkShop(shopData);
- if (shopRes.result !== true) throw new BusinessError(ErrorCode.DATA_INVALID, shopRes.msg);
- const { set } = setData;
- const stockList = [];
- for (const sd of set) {
- const { goods, spec, set_num } = sd;
- const goodsData = await this.goodsModel.findById(goods);
- const goodsRes = this.ctx.service.util.trade.checkGoods(goodsData);
- if (goodsRes.result !== true) throw new BusinessError(ErrorCode.DATA_INVALID, goodsRes.msg);
- const goodsSpecData = await this.goodsSpecModel.findById(spec);
- const setGoodsNum = this.ctx.multiply(buyNum, set_num);
- const gsRes = this.ctx.service.util.trade.checkGoodsSpec(goodsSpecData, setGoodsNum, '0');
- if (gsRes.result !== true) throw new BusinessError(ErrorCode.DATA_INVALID, gsRes.msg);
- const { num: gsnum = 0 } = goodsSpecData;
- // 应该用 库存/每套的件数 向下取整作为库存量
- const stock_num = _.floor(this.ctx.divide(gsnum, set_num));
- stockList.push(stock_num);
- }
- const total = _.min(stockList);
- return { enough: true, total, shop };
- }
- /**
- * 检查商品规格的库存
- * @param {String} goodsSpecId 商品规格id
- * @param {String} cartId 购物车id
- * @param {Number} num 需要的库存数量
- * @param {Boolean} update 修改购物车
- * @param {String} set_id 套装id
- * @return {Boolean} true:库存满足购物车条件;false:库存不满足条件
- */
- async checkGoodsNum({ cartId, goodsSpecId, num, set_id }, update = true) {
- if (set_id) {
- // 套装查询库存
- const cartData = await this.model.findById(cartId);
- const res = await this.checkSetGoodsNum(cartData, num);
- if (update && cartId) {
- await this.model.updateOne({ _id: cartId }, { num });
- }
- return res;
- }
- const { populate } = this.ctx.service.shop.goodsSpec.getRefMods();
- const goodsSpec = await this.goodsSpecModel.findById(goodsSpecId).populate(populate);
- if (!goodsSpec) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到商品的规格数据');
- const goods = _.get(goodsSpec, 'goods');
- const shop = _.get(goods, 'shop');
- const shopRes = this.ctx.service.util.trade.checkShop(shop);
- if (shopRes.result !== true) throw new BusinessError(ErrorCode.DATA_INVALID, shopRes.msg);
- const goodsRes = this.ctx.service.util.trade.checkGoods(goods);
- if (goodsRes.result !== true) throw new BusinessError(ErrorCode.DATA_INVALID, goodsRes.msg);
- const gsRes = this.ctx.service.util.trade.checkGoodsSpec(goodsSpec, num);
- const { num: gsnum = 0 } = goodsSpec;
- if (gsRes.result !== true) {
- return { enough: false, total: gsnum, msg: gsRes.msg };
- }
- if (update && cartId) {
- await this.model.updateOne({ _id: cartId }, { num });
- }
- return { enough: true, total: gsnum };
- }
- }
- module.exports = CartService;
|