group.js 6.5 KB

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