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.

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