group.js 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  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 moment = require('moment');
  7. const { ObjectId } = require('mongoose').Types;
  8. //
  9. class GroupService extends CrudService {
  10. constructor(ctx) {
  11. super(ctx, 'group');
  12. this.model = this.ctx.model.Group.Group;
  13. this.goodsModel = this.ctx.model.Shop.Goods;
  14. this.goodsSpecModel = this.ctx.model.Shop.GoodsSpec;
  15. this.userModel = this.ctx.model.User.User;
  16. this.orderModel = this.ctx.model.Trade.Order;
  17. }
  18. /**
  19. * 生成团
  20. * @param {Object} orderDetail 订单详情数据
  21. * @param {Transaction} tran 数据库事务实例
  22. */
  23. async create(orderDetail, tran) {
  24. const { goods: goodsInfos, customer, shop } = orderDetail;
  25. const g = _.head(goodsInfos);
  26. const goods_id = _.get(g, 'goods._id');
  27. const goods = await this.goodsModel.findById(goods_id);
  28. const goodsSpec_id = _.get(g, '_id');
  29. const goodsSpec = await this.goodsSpecModel.findById(goodsSpec_id);
  30. const person_limit = _.get(goodsSpec, 'group_config.need_person');
  31. const leader = customer;
  32. const persons = [{ customer, status: '0', join_time: moment().format('YYYY-MM-DD HH:mm:ss') }];
  33. const obj = { shop, goods, goodsSpec, leader, persons, person_limit };
  34. const id = tran.insert('Group', obj);
  35. return id;
  36. }
  37. /**
  38. * 加入团
  39. * @param {String} customer 用户id
  40. * @param {String} group_id 团id
  41. * @param {Transaction} tran 数据库事务实例
  42. */
  43. async join(customer, group_id, tran) {
  44. const result = await this.checkGroupCanJoin({ id: group_id, customer });
  45. if (!result.result) throw new BusinessError(ErrorCode.DATA_INVALID, result.msg);
  46. const data = await this.model.findById(group_id);
  47. if (!data) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到团信息');
  48. const { persons = [], person_limit } = data;
  49. const nps = JSON.parse(JSON.stringify(persons));
  50. nps.push({ customer, status: '0', join_time: moment().format('YYYY-MM-DD HH:mm:ss') });
  51. const updateData = { persons: nps };
  52. if (person_limit <= nps.length) updateData.status = '1';
  53. tran.update('Group', group_id, updateData);
  54. }
  55. // 检查是否可以加入团
  56. async checkGroupCanJoin({ id, customer }) {
  57. const data = await this.model.findById(id);
  58. if (!data) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到团数据');
  59. const { person_limit, persons = [], status } = data;
  60. if (status === '1') return { result: false, msg: '当前团已结束' };
  61. else if (status === '-1') return { result: false, msg: '当前团已关闭' };
  62. // 检查是否已经参团
  63. const cus = _.get(this.ctx, 'user._id', customer);
  64. if (!cus) throw new BusinessError(ErrorCode.NOT_LOGIN, '用户未登录');
  65. const r = data.persons.find(f => f.customer === cus);
  66. if (r) return { result: false, msg: '您已参团' };
  67. // 为0是正常的团员
  68. const realPersons = persons.filter(f => f.status === '0');
  69. if (realPersons.length < person_limit) return { result: true };
  70. return { result: false, msg: '当前参团人数已足够' };
  71. }
  72. /**
  73. * 团购退货(订单取消&售后退款/退货)
  74. * @param {Object} params 参数
  75. * @param params.group 团id
  76. * @param params.customer 用户id
  77. * @param tran
  78. */
  79. async refund({ group, customer }, tran) {
  80. let groupData = await this.model.findById(group);
  81. if (!groupData) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到拼团数据');
  82. groupData = JSON.parse(JSON.stringify(groupData));
  83. const { persons, leader, status } = groupData;
  84. // 检查团状态,如果已经结束,就不需要该团这边的数据了
  85. if (status !== '0') return;
  86. const newPersons = JSON.parse(JSON.stringify(persons));
  87. const findPersonCondition = (c1, c2) => ObjectId(c1).equals(c2);
  88. const p = newPersons.find(f => findPersonCondition(f.customer, customer));
  89. if (!p) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到要退团的用户');
  90. const i = newPersons.findIndex(f => findPersonCondition(f.customer, customer));
  91. p.status = '1';
  92. p.out_time = moment().format('YYYY-MM-DD HH:mm:ss');
  93. newPersons[i] = p;
  94. const updateData = { persons: newPersons };
  95. // 团长退团了,根据入团时间降序,顺位成为团长
  96. if (ObjectId(leader).equals(customer)) {
  97. let newLeader;
  98. const orderList = _.orderBy(newPersons.filter(f => f.customer !== customer), [ 'status', 'join_time' ], [ 'asc', 'asc' ]);
  99. const head = _.head(orderList);
  100. if (head && head.status === '0') {
  101. newLeader = _.get(head, 'customer');
  102. updateData.leader = newLeader;
  103. }
  104. }
  105. // 判断是否都退团了
  106. const allRefund = newPersons.every(e => e.status === '1');
  107. if (allRefund) updateData.status = '-1';
  108. tran.update('Group', group, updateData);
  109. }
  110. /**
  111. * 获取团信息
  112. * @param {Object} query 地址参数
  113. * @param {String} query.order_id 订单id
  114. */
  115. async getGroup({ order_id }) {
  116. assert(order_id, '缺少订单信息');
  117. const order = await this.orderModel.findById(order_id, { group: 1, customer: 1 });
  118. if (!order) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到订单信息');
  119. let group = _.get(order, 'group');
  120. if (!ObjectId.isValid(group)) {
  121. const customer = _.get(order, 'customer');
  122. const groupData = await this.model.findOne({ 'persons.customer': customer }, { _id: 1 }).sort({ 'meta.createdAt': -1 });
  123. group = _.get(groupData, '_id');
  124. }
  125. return group;
  126. }
  127. async beforeQuery(filter) {
  128. const gsv = _.get(filter, 'goodsSpec._id');
  129. if (gsv) filter['goodsSpec._id'] = ObjectId(gsv);
  130. const gv = _.get(filter, 'goods._id');
  131. if (gv) filter['goods._id'] = ObjectId(gv);
  132. const p = _.get(filter, 'persons.customer');
  133. if (p) {
  134. filter['persons.status'] = '0';
  135. }
  136. return filter;
  137. }
  138. async afterQuery(filter, data) {
  139. data = JSON.parse(JSON.stringify(data));
  140. for (const i of data) {
  141. const { persons = [] } = i;
  142. for (const p of persons) {
  143. const user = await this.getUserInfo(p.customer);
  144. p.name = _.get(user, 'name');
  145. p.icon = _.get(user, 'icon');
  146. }
  147. }
  148. return data;
  149. }
  150. async afterFetch(filter, data) {
  151. data = JSON.parse(JSON.stringify(data));
  152. const { persons = [] } = data;
  153. for (const p of persons) {
  154. const user = await this.getUserInfo(p.customer);
  155. p.name = _.get(user, 'name');
  156. p.icon = _.get(user, 'icon');
  157. }
  158. return data;
  159. }
  160. async getUserInfo(id) {
  161. const user = await this.userModel.findById(id, { name: 1, icon: 1 });
  162. return user;
  163. }
  164. }
  165. module.exports = GroupService;