cart.js 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. 'use strict';
  2. const { CrudService } = require('naf-framework-mongoose-free/lib/service');
  3. const { BusinessError, ErrorCode } = require('naf-core').Error;
  4. const _ = require('lodash');
  5. const assert = require('assert');
  6. const { ObjectId } = require('mongoose').Types;
  7. //
  8. class CartService extends CrudService {
  9. constructor(ctx) {
  10. super(ctx, 'cart');
  11. this.model = this.ctx.model.Trade.Cart;
  12. this.goodsSpecModel = this.ctx.model.Shop.GoodsSpec;
  13. this.platformActModel = this.ctx.model.System.PlatformAct;
  14. this.gjaModel = this.ctx.model.Shop.GoodsJoinAct;
  15. }
  16. /**
  17. * 返回购物车需要的数据格式
  18. ** 添加促销部分:
  19. ** 买赠,特价,加价购: 需要查询每个商品是否参与了这三项活动,需要给出对应数据
  20. ** 满减/折:不需要在购物车出现
  21. ** 套装:最后下单时组合,购物车中不需要额外修改
  22. * @param {Object} query 查询条件
  23. * @param query.customer 顾客id
  24. * @return {Array}
  25. */
  26. async selfCart({ customer }) {
  27. assert(customer, '缺少顾客信息');
  28. let data = await this.model.find({ customer });
  29. if (data.length > 0) {
  30. data = JSON.parse(JSON.stringify(data));
  31. data = data.map(i => ({ ...i, cart_id: i._id }));
  32. }
  33. data = await this.getCartGoodsAct(data);
  34. const actList = await this.ctx.service.trade.order.getActList(data);
  35. const pageData = await this.ctx.service.trade.order.getPageData(data, actList);
  36. return pageData;
  37. }
  38. /**
  39. * 实时获取购物车内的商品参与的活动
  40. * @param {Array} data 购物车商品
  41. */
  42. async getCartGoodsAct(data) {
  43. data = data.map(i => ({ ...i, act: [] }));
  44. // 实时匹配活动问题
  45. const platformActList = await this.platformActModel.find({ is_use: '0' });
  46. const platform_act = platformActList.map(i => ObjectId(i._id).toString());
  47. for (const cart of data) {
  48. const { goodsSpec: spec_id, goods: goods_id, act = [] } = cart;
  49. const gjaList = await this.gjaModel.find({ platform_act, 'goods._id': ObjectId(goods_id).toString(), 'spec._id': ObjectId(spec_id).toString() });
  50. for (const gja of gjaList) {
  51. const { platform_act_type: type, platform_act } = gja;
  52. // 加价购需要额外判断是否是基础商品
  53. if (type === '4') {
  54. const goods_type = _.get(gja, 'config.goods_type');
  55. if (goods_type === 'basic') act.push(platform_act);
  56. } else act.push(platform_act);
  57. }
  58. cart.act = _.uniq(act);
  59. }
  60. return data;
  61. }
  62. /**
  63. ** 创建购物车信息,若找到该店的该商品规格.进行库存校验
  64. ** 数量进行合并;
  65. ** 反之创建
  66. ** 添加促销活动部分:
  67. ** 买赠,特价,加价购: 不需要在创建时处理,而是在查询时实时处理,显示相关信息
  68. ** 满减/折:不需要在购物车出现
  69. ** 套装:只有套装需要记录在购物车中,以同一商品形式出现
  70. * @param {Object} body 请求参数
  71. * @param body.num 数量
  72. */
  73. async create({ num, ...body }) {
  74. const { customer, shop, goods, goodsSpec } = body;
  75. assert(customer, '缺少顾客信息');
  76. assert(shop, '缺少店铺信息');
  77. assert(goods, '缺少商品信息');
  78. assert(goodsSpec, '缺少商品规格信息');
  79. const query = _.pick(body, [ 'customer', 'shop', 'goods', 'goodsSpec' ]);
  80. const data = await this.model.findOne(query);
  81. if (data) {
  82. const buyNum = this.ctx.plus(data.num, num);
  83. const { enough } = await this.checkGoodsNum({ goodsSpecId: goodsSpec, num: buyNum });
  84. if (!enough) throw new BusinessError(ErrorCode.SERVICE_FAULT, '库存不足,无法添加至购物车');
  85. data.num = buyNum;
  86. await data.save();
  87. } else {
  88. const { enough } = await this.checkGoodsNum({ goodsSpecId: goodsSpec, num });
  89. if (!enough) throw new BusinessError(ErrorCode.SERVICE_FAULT, '库存不足,无法添加至购物车');
  90. await this.model.create({ num, ...body });
  91. }
  92. }
  93. /**
  94. * 检查商品规格的库存
  95. * @param {String} goodsSpecId 商品规格id
  96. * @param {String} cartId 购物车id
  97. * @param {Number} num 需要的库存数量
  98. * @param {Boolean} update 修改购物车
  99. * @return {Boolean} true:库存满足购物车条件;false:库存不满足条件
  100. */
  101. async checkGoodsNum({ cartId, goodsSpecId, num }, update = true) {
  102. const { populate } = this.ctx.service.shop.goodsSpec.getRefMods();
  103. const goodsSpec = await this.goodsSpecModel.findById(goodsSpecId).populate(populate);
  104. if (!goodsSpec) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到商品的规格数据');
  105. const goods = _.get(goodsSpec, 'goods');
  106. const shop = _.get(goods, 'shop');
  107. const shopRes = this.ctx.service.util.trade.checkShop(shop);
  108. if (shopRes.result !== true) throw new BusinessError(ErrorCode.DATA_INVALID, shopRes.msg);
  109. const goodsRes = this.ctx.service.util.trade.checkGoods(goods);
  110. if (goodsRes.result !== true) throw new BusinessError(ErrorCode.DATA_INVALID, goodsRes.msg);
  111. const gsRes = this.ctx.service.util.trade.checkGoodsSpec(goodsSpec, num);
  112. const { num: gsnum = 0 } = goodsSpec;
  113. if (gsRes.result !== true) {
  114. return { enough: false, total: gsnum, msg: gsRes.msg };
  115. }
  116. if (update && cartId) {
  117. await this.model.updateOne({ _id: cartId }, { num });
  118. }
  119. return { enough: true, total: gsnum };
  120. }
  121. }
  122. module.exports = CartService;