You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

203 lines
7.4 KiB

5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
  1. <?php
  2. namespace App\Service\v3\Implementations;
  3. use App\Commons\Log;
  4. use App\Constants\v3\ActivityType;
  5. use App\Constants\v3\ErrorCode;
  6. use App\Constants\v3\LogLabel;
  7. use App\Constants\v3\SsdbKeys;
  8. use App\Service\v3\Interfaces\GoodsActivityServiceInterface;
  9. use App\TaskWorker\SSDBTask;
  10. use App\Model\v3\GoodsActivity;
  11. use App\Model\v3\GoodsActivityBanner;
  12. use Hyperf\Redis\Redis;
  13. use Hyperf\Utils\ApplicationContext;
  14. use Hyperf\Di\Annotation\Inject;
  15. class GoodsActivityService implements GoodsActivityServiceInterface
  16. {
  17. /**
  18. * @Inject
  19. * @var Log
  20. */
  21. protected $log;
  22. public function do($goodsId)
  23. {
  24. }
  25. public function check(GoodsActivity $goods, $num, $userId)
  26. {
  27. $redis = ApplicationContext::getContainer()->get(Redis::class);
  28. $inventoryKey = 'goods_inventory_sold_2_'.$goods->id; // 拼接activity_type和goods_id
  29. if (empty($goods)) {
  30. $message = ErrorCode::getMessage(ErrorCode::GOODS_ACTIVITY_NOT_EXISTS);
  31. $this->log->event(LogLabel::ERROR_CODE_EXCEPTION_LOG_DATA, ['message' => $message, 'buy_num' => $num, 'user_id' => $userId, 'logData' => json_encode($goods)]);
  32. return ErrorCode::GOODS_ACTIVITY_NOT_EXISTS;
  33. }
  34. // 活动是否已经结束
  35. if ($goods->expire_time < time()) {
  36. $message = ErrorCode::getMessage(ErrorCode::GOODS_ACTIVITY_EXPIRED);
  37. $this->log->event(LogLabel::ERROR_CODE_EXCEPTION_LOG_DATA, ['message' => $message, 'buy_num' => $num, 'user_id' => $userId, 'logData' => json_encode($goods)]);
  38. return ErrorCode::GOODS_ACTIVITY_EXPIRED;
  39. }
  40. // 商户歇业
  41. if($goods->store->is_rest == 1){
  42. $message = ErrorCode::getMessage(ErrorCode::STORE_REST);
  43. $this->log->event(LogLabel::ERROR_CODE_EXCEPTION_LOG_DATA, ['message' => $message, 'buy_num' => $num, 'user_id' => $userId, 'logData' => json_encode($goods)]);
  44. return ErrorCode::STORE_REST;
  45. }
  46. // 商品下架或已删除
  47. if($goods->on_sale == 0 || !is_null($goods->deleted_at)){
  48. $message = ErrorCode::getMessage(ErrorCode::GOODS_ACTIVITY_ON_SALE_NO);
  49. $this->log->event(LogLabel::ERROR_CODE_EXCEPTION_LOG_DATA, ['message' => $message, 'buy_num' => $num, 'user_id' => $userId, 'logData' => json_encode($goods)]);
  50. return ErrorCode::GOODS_ACTIVITY_ON_SALE_NO;
  51. }
  52. // 商品库存不足
  53. // 获取冻结的库存
  54. $inventoryFrozen = (int)$redis->get($inventoryKey);
  55. // $inventoryFrozen = 0;
  56. if($goods->is_infinite != 1 && $goods->inventory < ($num+$inventoryFrozen)){
  57. $message = ErrorCode::getMessage(ErrorCode::GOODS_ACTIVITY_INVENTORY_ERROR);
  58. $this->log->event(LogLabel::ERROR_CODE_EXCEPTION_LOG_DATA, ['message' => $message, 'buy_num' => $num, 'inventoryKey' => $inventoryKey, 'inventoryFrozen' => $inventoryFrozen, 'user_id' => $userId, 'logData' => json_encode($goods)]);
  59. return ErrorCode::GOODS_ACTIVITY_INVENTORY_ERROR;
  60. }
  61. // 是否超过限购数量
  62. if ($goods->restrict_num != 0 && $goods->restrict_num < $num) {
  63. $message = ErrorCode::getMessage(ErrorCode::GOODS_ACTIVITY_RESTRICT_LIMIT);
  64. $this->log->event(LogLabel::ERROR_CODE_EXCEPTION_LOG_DATA, ['message' => $message, 'buy_num' => $num, 'user_id' => $userId, 'logData' => json_encode($goods)]);
  65. return ErrorCode::GOODS_ACTIVITY_RESTRICT_LIMIT;
  66. }
  67. // 是否已经购买过(某个时间段内,时间段有商品的限制)
  68. $ssdb = ApplicationContext::getContainer()->get(SSDBTask::class);
  69. $hasBuy = $ssdb->exec('get', SsdbKeys::ACTIVITY_GOODS_BUY_RECORD.$userId.'_'.$goods->type.'_'.$goods->id);
  70. if ($hasBuy && $hasBuy >= $goods->time_limit_num) {
  71. $message = ErrorCode::getMessage(ErrorCode::GOODS_ACTIVITY_BUY);
  72. $this->log->event(LogLabel::ERROR_CODE_EXCEPTION_LOG_DATA, ['message' => $message, 'has_buy' => $hasBuy, 'ssdb_key' => SsdbKeys::ACTIVITY_GOODS_BUY_RECORD.$userId.'_'.$goods->type.'_'.$goods->id, 'buy_num' => $num, 'user_id' => $userId, 'logData' => json_encode($goods)]);
  73. return ErrorCode::GOODS_ACTIVITY_BUY;
  74. }
  75. return true;
  76. }
  77. public function undo()
  78. {
  79. // TODO: Implement undo() method.
  80. }
  81. public function getBanner($goodsId)
  82. {
  83. $banner = GoodsActivityBanner::query()->where('goods_id',$goodsId)->orderByDesc('type')->get();
  84. return $banner;
  85. }
  86. public function detail($goodsId)
  87. {
  88. $res = GoodsActivity::query()->with('store')->where('id',$goodsId)->first();
  89. return $res;
  90. }
  91. public function cacheRecord($goodsId, $num, $userId)
  92. {
  93. $goods = GoodsActivity::query()
  94. ->where('id', $goodsId)
  95. ->first();
  96. $ssdbKey = SsdbKeys::ACTIVITY_GOODS_BUY_RECORD.$userId.'_'.$goods->type.'_'.$goodsId;
  97. $expireTime = 0;
  98. if ($goods->time_limit_days >= 1) {
  99. $expireTime += strtotime(date('Y-m-d 23:59:59')) - time();
  100. $expireTime += ($goods->time_limit_days-1) * 86400;
  101. } elseif ($goods->time_limit_days > 0 && $goods->time_limit_days < 1) {
  102. $expireTime += bcmul($goods->time_limit_days,86400,0);
  103. } else {
  104. return;
  105. }
  106. $ssdb = ApplicationContext::getContainer()->get(SSDBTask::class);
  107. if (!$ssdb->exec('exists', $ssdbKey)) {
  108. $ssdb->exec('set', $ssdbKey, $num);
  109. $ssdb->exec('expire', $ssdbKey, $expireTime);
  110. } else {
  111. $ssdb->exec('incr', $ssdbKey, $num);
  112. }
  113. }
  114. public function clearCacheRecord($goodsId, $num, $userId)
  115. {
  116. $goods = GoodsActivity::query()
  117. ->where('id', $goodsId)
  118. ->first();
  119. if (empty($goods)) {
  120. return true;
  121. }
  122. $ssdbKey = SsdbKeys::ACTIVITY_GOODS_BUY_RECORD.$userId.'_'.$goods->type.'_'.$goodsId;
  123. $ssdb = ApplicationContext::getContainer()->get(SSDBTask::class);
  124. if ($ssdb->exec('exists', $ssdbKey)) {
  125. $res = $ssdb->exec('incr', $ssdbKey, -1*$num);
  126. }
  127. }
  128. /**
  129. * 统计订单中活动商品的数量,并校验
  130. * @param $goodsIds
  131. * @param int $limitNum
  132. * @return bool
  133. */
  134. public function checkOrderActivityCount($goodsIds, $limitNum=1)
  135. {
  136. $sourceGoods = GoodsActivity::query()
  137. ->whereIn('id', $goodsIds)
  138. ->get()->toArray();
  139. $redis = ApplicationContext::getContainer()->get(Redis::class);
  140. $activityTypeLimitNumsKey = 'activity_type_limit_nums';
  141. $limitNums = $redis->hGetAll($activityTypeLimitNumsKey);
  142. if (empty($limitNums)) {
  143. $limitNums = [
  144. ActivityType::FLASH_SALE => 0,
  145. ActivityType::GROUP_BUY => 0,
  146. ActivityType::NEW_PRODUCT => 0,
  147. ];
  148. }
  149. $buyNum = [
  150. ActivityType::FLASH_SALE => 0,
  151. ActivityType::GROUP_BUY => 0,
  152. ActivityType::NEW_PRODUCT => 0,
  153. ];
  154. foreach ($sourceGoods as $key => &$goods) {
  155. if ($limitNums[$goods['type']] == 0) { // 不限制同类购买商品种数,也就是可以同时购买多款不同商品
  156. continue;
  157. }
  158. $buyNum[$goods['type']] += 1;
  159. if ($buyNum[$goods['type']] > $limitNums[$goods['type']]) {
  160. return false;
  161. }
  162. }
  163. return true;
  164. }
  165. }