zrOrder.js 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  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. //
  7. class ZrOrderService extends CrudService {
  8. constructor(ctx) {
  9. super(ctx, 'zrorder');
  10. this.redis = this.app.redis;
  11. this.redisKey = this.app.config.redisKey;
  12. this.redisTimeout = this.app.config.redisTimeout;
  13. this.model = this.ctx.model.ZrOrder;
  14. this.goodsModel = this.ctx.model.ZrGoods;
  15. this.pointModel = this.ctx.model.Base.Point;
  16. this.shopModel = this.ctx.model.Base.Shop;
  17. this.addressModel = this.ctx.model.Base.Address;
  18. }
  19. // 进入订单页前,通过函数判断,存储是否可以购买 指定商品 的 指定数量
  20. // 下单,走同样的函数判断.
  21. // 直接生成订单,扣除积分
  22. async toMakeOrder({ key }) {
  23. key = `${this.redisKey.orderKeyPrefix}${key}`;
  24. let data = await this.redis.get(key);
  25. if (!data) throw new BusinessError(ErrorCode.SERVICE_FAULT, '请求超时,请重新进入下单页');
  26. data = JSON.parse(data);
  27. const { shop, goods, num: buy_num } = data;
  28. // 店铺信息
  29. const shopInfo = await this.shopModel.findById(shop);
  30. // 商品信息
  31. const goodsInfo = await this.goodsModel.findById(goods);
  32. // 消耗积分
  33. const costTotal = this.ctx.multiply(_.get(goodsInfo, 'cost'), buy_num);
  34. // 积分信息
  35. const customer = _.get(this.ctx.user, '_id');
  36. const points = await this.pointComputedTotal({ customer });
  37. // 地址信息
  38. const address = await this.addressModel.findOne({ customer, is_default: '1' });
  39. return { buy_num, shop: shopInfo, goods: goodsInfo, points, address, costTotal };
  40. }
  41. /**
  42. * 检查是否可以购买商品,并生成缓存
  43. * @param {Object} body 参数体
  44. * @param body.shop 店铺id
  45. * @param body.goods 尊荣商品id
  46. * @param body.num 购买数量
  47. * @param {Boolean} makeCache 是否生成缓存
  48. */
  49. async checkCanBuy({ shop, goods, num }, makeCache = true) {
  50. const result = { result: true };
  51. const shopInfo = await this.shopModel.findById(shop);
  52. if (!shopInfo || _.get(shopInfo, '1')) {
  53. result.result = false;
  54. result.msg = '店铺当前不处于营业状态';
  55. return result;
  56. }
  57. const goodsInfo = await this.goodsModel.findById(goods);
  58. if (!goodsInfo) {
  59. result.result = false;
  60. result.msg = '未找到尊荣商品';
  61. return result;
  62. }
  63. const user = this.ctx.user;
  64. const customer = _.get(user, '_id');
  65. if (!customer) {
  66. result.result = false;
  67. result.msg = '未找到用户信息';
  68. }
  69. // #region 库存判断
  70. const knum = _.get(goodsInfo, 'num');
  71. const res = this.ctx.minus(knum, num);
  72. if (res <= 0) {
  73. result.result = false;
  74. result.msg = '库存不足';
  75. return result;
  76. }
  77. // #endregion
  78. // #region 积分判断
  79. const pointTotal = await this.pointComputedTotal({ customer });
  80. // 计算购买所需积分
  81. const cost = _.get(goodsInfo, 'cost', 0);
  82. if (cost === 0) {
  83. result.result = false;
  84. result.msg = '商品设置的尊荣有误,无法进行购买';
  85. return result;
  86. }
  87. const costTotal = this.ctx.multiply(cost, num);
  88. const afterCost = this.ctx.minus(pointTotal, costTotal);
  89. if (afterCost < 0) {
  90. result.result = false;
  91. result.msg = '您的积分不足';
  92. return result;
  93. }
  94. // #endregion
  95. if (makeCache) {
  96. const key = await this.makeOrderKey({ shop, goods, num });
  97. result.key = key;
  98. }
  99. return result;
  100. }
  101. // 生成key
  102. async makeOrderKey(data) {
  103. const str = this.createNonceStr();
  104. const key = `${this.redisKey.orderKeyPrefix}${str}`;
  105. const value = JSON.stringify(data);
  106. await this.redis.set(key, value, 'EX', this.redisTimeout);
  107. return str;
  108. }
  109. /**
  110. * 计算用户的积分
  111. * @param {Object} data 数据对象
  112. * @param data.customer 用户数据id
  113. */
  114. async pointComputedTotal({ customer }) {
  115. assert(customer, '缺少用户信息');
  116. const res = await this.pointModel.find({ customer });
  117. const total = res.reduce((p, n) => {
  118. let point = n.point;
  119. if (!(n.source === '0' || n.source === '1')) point = -point;
  120. return this.ctx.plus(p, point);
  121. }, 0);
  122. return total;
  123. }
  124. // 随机字符串产生函数
  125. createNonceStr() {
  126. return Math.random().toString(36).substr(2, 15);
  127. }
  128. }
  129. module.exports = ZrOrderService;