Kan.php 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. <?php
  2. namespace addons\shopro\library\activity\provider;
  3. use addons\shopro\service\StockSale;
  4. use addons\shopro\exception\ShoproException;
  5. /**
  6. * 砍价
  7. */
  8. class Kan extends Base
  9. {
  10. protected $rules = [
  11. "is_commission" => "require|boolean",
  12. "is_free_shipping" => "require|boolean",
  13. "sales_show_type" => "require",
  14. "limit_num" => "number|egt:0",
  15. "order_auto_close" => "float|egt:0",
  16. "team_num" => "require|number|egt:0",
  17. ];
  18. protected $message = [
  19. 'team_num.require' => '请填写最多砍价人数',
  20. ];
  21. protected $default = [
  22. "is_commission" => 0, // 是否参与分销
  23. "is_free_shipping" => 0, // 是否包邮
  24. "sales_show_type" => "real", // real=真实活动销量|goods=商品总销量(包含虚拟销量)
  25. "limit_num" => 0, // 每人限购数量 0:不限购
  26. "order_auto_close" => 0, // 订单自动关闭时间,如果为 0 将使用系统级订单自动关闭时间
  27. "team_num" => 2, // 砍价人数,最少两人
  28. ];
  29. public function check($params, $activity_id = 0)
  30. {
  31. // 数据验证
  32. $params = parent::check($params);
  33. // 验证添加的活动商品是否至少设置了一个活动规格
  34. $this->checkActivitySkuPrice($params['goods_list']);
  35. // 检测活动之间是否存在冲突
  36. $this->checkActivityConflict($params, $params['goods_list'], $activity_id);
  37. return $params;
  38. }
  39. public function save($activity, $params = [])
  40. {
  41. $goodsList = $params['goods_list'];
  42. $this->saveSkuPrice($goodsList, $activity);
  43. }
  44. public function recoverSkuPrices($goods, $activity)
  45. {
  46. $activitySkuPrices = $activity['activity_sku_prices'];
  47. $skuPrices = $goods->sku_prices;
  48. foreach ($skuPrices as $key => &$skuPrice) {
  49. $stock = $skuPrice->stock; // 下面要用
  50. $skuPrice->stock = 0;
  51. $skuPrice->sales = 0;
  52. foreach ($activitySkuPrices as $activitySkuPrice) {
  53. if ($skuPrice['id'] == $activitySkuPrice['goods_sku_price_id']) {
  54. // 采用活动的 规格内容
  55. $skuPrice->old_price = $skuPrice->price; // 保存原始普通商品规格的价格(计算活动的优惠)
  56. $skuPrice->stock = ($activitySkuPrice['stock'] > $stock) ? $stock : $activitySkuPrice['stock']; // 活动库存不能超过商品库存
  57. $skuPrice->sales = $activitySkuPrice['sales'];
  58. $skuPrice->price = $activitySkuPrice['price'];
  59. $skuPrice->status = $activitySkuPrice['status']; // 采用活动的上下架
  60. $skuPrice->min_price = $activitySkuPrice['price']; // 当前活动规格最小价格,这里是秒杀价
  61. $skuPrice->max_price = $activitySkuPrice['price']; // 用作计算活动中最大价格
  62. // 记录相关活动类型
  63. $skuPrice->activity_type = $activity['type'];
  64. $skuPrice->activity_id = $activity['id'];
  65. // 下单的时候需要存活动 的 sku_price_id)
  66. $skuPrice->item_goods_sku_price = $activitySkuPrice;
  67. break;
  68. }
  69. }
  70. }
  71. return $skuPrices;
  72. }
  73. /**
  74. * 这里要使用 shoproException 抛出异常
  75. *
  76. * @param array $buyInfo
  77. * @param array $activity
  78. * @return array
  79. */
  80. public function buyCheck($buyInfo, $activity)
  81. {
  82. $buy_type = request()->param('buy_type', 'kan');
  83. $groupon_id = request()->param('kan_id', 0);
  84. // 拼团
  85. $rules = $activity['rules'];
  86. $currentSkuPrice = $buyInfo['current_sku_price'];
  87. $is_leader_discount = $currentSkuPrice['is_leader_discount'];
  88. // 成团人数
  89. $num = $rules['team_num'] ?? 1;
  90. // 额外需要的库存
  91. $need_add_num = 0;
  92. // 要单独购买
  93. if ($buy_type == 'alone') {
  94. // 不允许单独购买
  95. if (!$is_alone) {
  96. throw new ShoproException('该商品不允许单独购买');
  97. }
  98. } else {
  99. // 拼团,临时将拼团价设置为商品价格
  100. if (!$groupon_id && $is_leader_discount) {
  101. // 开新团,并且有团长优惠,使用优惠价格
  102. $buyInfo['current_sku_price']['price'] = $currentSkuPrice['leader_price'];
  103. } else {
  104. // 参与团,或者没有团长优惠
  105. $buyInfo['current_sku_price']['price'] = $currentSkuPrice['groupon_price'];
  106. }
  107. }
  108. // 如果是开新团
  109. if (!$groupon_id && $buy_type == 'groupon') {
  110. // 开团需要的最小库存
  111. $need_add_num = ($num - 1);
  112. }
  113. // 当前库存,小于要购买的数量
  114. $need_num = $buyInfo['goods_num'] + ($need_add_num ?? 0);
  115. if ($currentSkuPrice['stock'] < $need_num) {
  116. if ($need_add_num && $is_alone && !$groupon_id && $buy_type == 'groupon') {
  117. throw new ShoproException('商品库存不足以开团,请选择单独购买');
  118. } else if ($buy_type == 'alone') {
  119. throw new ShoproException('商品库存不足');
  120. } else {
  121. throw new ShoproException('该商品不允商品库存不足以开团许单独购买');
  122. }
  123. }
  124. $buyInfo['is_commission'] = $rules['is_commission'] ?? 0; // 是否参与分销
  125. return $buyInfo;
  126. }
  127. public function buy($buyInfo, $activity)
  128. {
  129. $user = auth_user();
  130. $buy_type = request()->param('buy_type', 'kan');
  131. $groupon_id = request()->param('kan_id', 0);
  132. // 参与现有团
  133. if ($buy_type != 'alone' && $groupon_id) {
  134. // 检测并获取要参与的团
  135. $activityGroupon = $this->checkAndGetJoinGroupon($buyInfo, $user, $groupon_id);
  136. }
  137. // 判断 并 增加 redis 销量
  138. $stockSale = new StockSale();
  139. $stockSale->cacheForwardSale($buyInfo);
  140. // (开新团不判断)参与旧团 增加预拼团人数,上面加入团的时候已经判断过一次了,所以这里 99.99% 会加入成功的
  141. if (isset($activityGroupon) && $activityGroupon) {
  142. // 增加拼团预成员人数
  143. $goods = $buyInfo['goods'];
  144. $activity = $goods['activity'];
  145. $this->grouponCacheForwardNum($activityGroupon, $activity, $user);
  146. }
  147. return $buyInfo;
  148. }
  149. public function buyOk($order, $user)
  150. {
  151. // 不需要处理
  152. }
  153. /**
  154. * 拼团购买失败
  155. *
  156. * @param \think\Model $order
  157. * @param string $type
  158. * @return void
  159. */
  160. public function buyFail($order, $type)
  161. {
  162. // 判断扣除预销量 (活动信息还在 redis)
  163. $stockSale = new StockSale();
  164. $stockSale->cacheBackSale($order);
  165. }
  166. }