RecommendRewardOrderService.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. <?php
  2. namespace addons\ScoreExpansion\common\services;
  3. use addons\ScoreExpansion\common\enums\ScoreExpansionEnum;
  4. use addons\ScoreExpansion\common\models\ScoreExpansionRecommendRewardDetails;
  5. use addons\ScoreExpansion\common\models\ScoreExpansionRecommendRewardGoods;
  6. use addons\ScoreExpansion\common\models\ScoreExpansionRecommendRewardOrder;
  7. use addons\ScoreExpansion\common\models\ScoreExpansionWallet;
  8. use common\enums\StatusEnum;
  9. use common\helpers\ArrayHelper;
  10. use common\helpers\FormatHelper;
  11. use common\models\mall\MallAddons;
  12. use common\models\order\Order;
  13. use common\models\user\User;
  14. use common\models\user\UserPartitionRelationship;
  15. use Exception;
  16. use RuntimeException;
  17. use Yii;
  18. class RecommendRewardOrderService extends BaseService
  19. {
  20. public $setting;
  21. /**
  22. * 创建推荐奖励订单
  23. *
  24. * @param int $orderId
  25. * @param int $eventType
  26. *
  27. * @return void
  28. */
  29. public function createRecommendRewardOrder(int $orderId, int $eventType)
  30. {
  31. $order = Order::find()
  32. ->where(['id' => $orderId, 'status' => StatusEnum::ENABLED])
  33. ->with(['detail'])
  34. ->asArray()
  35. ->one();
  36. if (!$order) {
  37. Yii::$app->custom->logs('【积分拓客】创建推荐奖励订单失败,订单不存在', compact('orderId', 'eventType'));
  38. return;
  39. }
  40. $this->mall_id = $order['mall_id'];
  41. if (!MallAddons::isInstall($this->mall_id, ScoreExpansionEnum::ADDONS_NAME)) {
  42. return;
  43. }
  44. $setting = $this->getSetting();
  45. if (!$this->checkIsCreate($orderId, $eventType)) {
  46. return;
  47. }
  48. $joinGoods = ScoreExpansionRecommendRewardGoods::find()
  49. ->where([
  50. 'mall_id' => $this->mall_id,
  51. 'status' => StatusEnum::ENABLED,
  52. 'goods_id' => array_column($order['detail'], 'goods_id')
  53. ])
  54. ->select('is_alone, goods_id, setting')
  55. ->indexBy('goods_id')
  56. ->all();
  57. if (!$joinGoods) {
  58. return;
  59. }
  60. // 创建推荐奖励订单
  61. $t = Yii::$app->db->beginTransaction();
  62. try {
  63. foreach ($order['detail'] as $detail) {
  64. if (!isset($joinGoods[$detail['goods_id']])) {
  65. continue;
  66. }
  67. $loopNum = $setting['loop_num'];
  68. $rewardFrozenScore = $setting['reward_frozen_score'];
  69. $joinGoodsItem = $joinGoods[$detail['goods_id']];
  70. if ($joinGoodsItem['is_alone'] && $joinGoodsItem['setting']) {
  71. $loopNum = $joinGoodsItem['setting']['loop_num'];
  72. $rewardFrozenScore = $joinGoodsItem['setting']['reward_frozen_score'];
  73. }
  74. if (
  75. ScoreExpansionRecommendRewardOrder::setData([
  76. 'mall_id' => $this->mall_id,
  77. 'user_id' => $order['user_id'],
  78. 'user_ids' => [],
  79. 'exclude_user_ids' => [],
  80. 'order_id' => $detail['order_id'],
  81. 'order_detail_id' => $detail['id'],
  82. 'reward_period' => $setting['reward_period'],
  83. 'reward_frozen_score' => $rewardFrozenScore,
  84. 'reward_person_count' => $setting['reward_person_count'],
  85. 'loop_num' => $loopNum,
  86. 'is_end' => (int)(!$loopNum || !$rewardFrozenScore || !$setting['reward_person_count']),
  87. ]) === false
  88. ) {
  89. throw new RuntimeException(ScoreExpansionRecommendRewardOrder::getStaticError());
  90. }
  91. }
  92. $t->commit();
  93. } catch (Exception $e) {
  94. $t->rollBack();
  95. Yii::$app->custom->logs(FormatHelper::exception($e, '【积分拓客】创建推荐奖励订单失败'), compact('orderId', 'eventType'));
  96. }
  97. }
  98. /**
  99. * @param bool $overwrite
  100. *
  101. * @return array
  102. */
  103. public function getSetting(bool $overwrite = false): array
  104. {
  105. if (!$this->setting || $overwrite) {
  106. $settingService = new SettingService(['mall_id' => $this->mall_id]);
  107. $this->setting = $settingService->getSetting();
  108. }
  109. return $this->setting;
  110. }
  111. /**
  112. * 检查配置是否创建推荐奖励订单
  113. *
  114. * @param int $orderId
  115. * @param int $eventType
  116. *
  117. * @return bool
  118. */
  119. private function checkIsCreate(int $orderId, int $eventType): bool
  120. {
  121. $setting = $this->getSetting();
  122. if (empty($setting['is_enable_buy_goods_give_frozen_score'])) {
  123. return false;
  124. }
  125. if ($eventType != $setting['gift_method']) {
  126. return false;
  127. }
  128. // 创建过则不再创建
  129. if (
  130. ScoreExpansionRecommendRewardOrder::find()
  131. ->where([
  132. 'mall_id' => $this->mall_id,
  133. 'status' => StatusEnum::ENABLED,
  134. 'order_id' => $orderId
  135. ])
  136. ->exists()
  137. ) {
  138. return false;
  139. }
  140. return true;
  141. }
  142. /**
  143. * 发放推荐奖励
  144. *
  145. * @return void
  146. */
  147. public function sendRecommendReward()
  148. {
  149. $date = date('Ymd');
  150. $setting = $this->getSetting(true);
  151. // 查询推荐奖励订单
  152. $find = ScoreExpansionRecommendRewardOrder::find();
  153. ScoreExpansionRecommendRewardOrder::paramPack([
  154. 'where' => [
  155. [
  156. 'mall_id' => $this->mall_id,
  157. 'status' => StatusEnum::ENABLED,
  158. 'is_end' => StatusEnum::DISABLED,
  159. ],
  160. ['<', 'last_exec_date', $date]
  161. ],
  162. ], $find);
  163. foreach ($find->batch(500) as $batchItem) {
  164. foreach ($batchItem as $item) {
  165. Yii::$app->custom->logs('【积分拓客】开始执行每日发放商品购买赠送冻结积分', ['recommend_reward_order_id' => $item['id'], 'date' => $date]);
  166. try {
  167. $rewardNum = $item->reward_frozen_score;
  168. $item->last_exec_date = $date;
  169. // 判断是否是第一轮
  170. if ($item->current_loop_num <= 1) {
  171. $userId = $item->user_id;
  172. if ($item->user_ids) {
  173. $userId = end($item->user_ids);
  174. }
  175. $parentIdArr = UserPartitionRelationship::getParentIdArr($userId);
  176. if (!$parentIdArr) {
  177. $item->next();
  178. $item->save();
  179. continue;
  180. }
  181. // 查询会员等级
  182. $parentUsers = User::find()
  183. ->where([
  184. 'id' => $parentIdArr,
  185. 'status' => StatusEnum::ENABLED,
  186. 'mall_id' => $this->mall_id,
  187. 'level' => $setting['level_condition']
  188. ])
  189. ->select('level, id')
  190. ->indexBy('id')
  191. ->asArray()
  192. ->all();
  193. $parentIdArr = array_reverse($parentIdArr);
  194. foreach ($parentIdArr as $parentId) {
  195. if (isset($parentUsers[$parentId])) {
  196. $findParentId = $parentId;
  197. break;
  198. }
  199. }
  200. if (empty($findParentId)) {
  201. $item->next();
  202. $item->save();
  203. continue;
  204. }
  205. $item->frozen_score_issued_total += $rewardNum;
  206. $userIds = $item->user_ids;
  207. $userIds[] = $findParentId;
  208. $item->user_ids = $userIds;
  209. if (count($item->user_ids) >= $item->reward_person_count) {
  210. $item->next();
  211. }
  212. $t = Yii::$app->db->beginTransaction();
  213. try {
  214. $item->save();
  215. $res = ScoreExpansionRecommendRewardDetails::setData([
  216. 'mall_id' => $this->mall_id,
  217. 'recommend_reward_order_id' => $item->id,
  218. 'user_id' => $findParentId,
  219. 'date' => $date,
  220. 'reward_frozen_score' => $rewardNum,
  221. 'loop_num' => 1,
  222. 'current_reward_person_index' => count($item->user_ids) - 1
  223. ]);
  224. if ($res === false) {
  225. throw new RuntimeException(ScoreExpansionRecommendRewardDetails::getStaticError());
  226. }
  227. // 发放奖励
  228. $res = ScoreExpansionWallet::setData([
  229. 'mall_id' => $this->mall_id,
  230. 'user_id' => $res['user_id'],
  231. 'is_frozen' => true,
  232. 'integral' => $res['reward_frozen_score'],
  233. 'source_table' => ScoreExpansionRecommendRewardDetails::tableName(),
  234. 'source_table_id' => $res['id'],
  235. 'from_type' => ScoreExpansionEnum::FROM_RECOMMEND_REWARD,
  236. 'desc' => '购买商品循环赠送冻结积分',
  237. ]);
  238. if ($res === false) {
  239. throw new RuntimeException(ScoreExpansionWallet::getStaticError());
  240. }
  241. $t->commit();
  242. } catch (Exception $e) {
  243. $t->rollBack();
  244. Yii::$app->custom->logs(FormatHelper::exception($e, '【积分拓客】每日发放商品购买赠送冻结积分失败'), ['item' => ArrayHelper::toArray($item), 'user_id' => $findParentId]);
  245. }
  246. continue;
  247. }
  248. // 第一轮之后就跑定下来的关系链 user_ids
  249. $userId = $item->user_ids[$item->current_reward_person_index];
  250. if (in_array($userId, $item->exclude_user_ids)) {
  251. $item->next();
  252. $item->save();
  253. continue;
  254. }
  255. // 判断这个用户的等级,是否判断条件
  256. if (
  257. !User::find()
  258. ->where([
  259. 'id' => $userId,
  260. 'status' => StatusEnum::ENABLED,
  261. 'mall_id' => $this->mall_id,
  262. 'level' => $setting['level_condition']
  263. ])
  264. ->exists()
  265. ) {
  266. $excludeUserIds = $item->exclude_user_ids;
  267. $excludeUserIds[] = $userId;
  268. $item->exclude_user_ids = $excludeUserIds;
  269. // 关系链所有用户都被排除了,直接结束
  270. if (count($item->exclude_user_ids) === count($item->user_ids)) {
  271. $item->is_end = StatusEnum::ENABLED;
  272. } else {
  273. $item->next();
  274. }
  275. $item->save();
  276. continue;
  277. }
  278. $t = Yii::$app->db->beginTransaction();
  279. try {
  280. $res = ScoreExpansionRecommendRewardDetails::setData([
  281. 'mall_id' => $this->mall_id,
  282. 'recommend_reward_order_id' => $item->id,
  283. 'user_id' => $userId,
  284. 'date' => $date,
  285. 'reward_frozen_score' => $rewardNum,
  286. 'loop_num' => $item->current_loop_num,
  287. 'current_reward_person_index' => $item->current_reward_person_index
  288. ]);
  289. if ($res === false) {
  290. throw new RuntimeException(ScoreExpansionRecommendRewardDetails::getStaticError());
  291. }
  292. // 发放奖励
  293. $res = ScoreExpansionWallet::setData([
  294. 'mall_id' => $this->mall_id,
  295. 'user_id' => $res['user_id'],
  296. 'is_frozen' => true,
  297. 'integral' => $res['reward_frozen_score'],
  298. 'source_table' => ScoreExpansionRecommendRewardDetails::tableName(),
  299. 'source_table_id' => $res['id'],
  300. 'from_type' => ScoreExpansionEnum::FROM_RECOMMEND_REWARD,
  301. 'desc' => '购买商品循环赠送冻结积分',
  302. ]);
  303. if ($res === false) {
  304. throw new RuntimeException(ScoreExpansionWallet::getStaticError());
  305. }
  306. $item->frozen_score_issued_total += $rewardNum;
  307. $item->next();
  308. $item->save();
  309. $t->commit();
  310. } catch (Exception $e) {
  311. $t->rollBack();
  312. Yii::$app->custom->logs(FormatHelper::exception($e, '【积分拓客】每日发放商品购买赠送冻结积分失败'), ['item' => ArrayHelper::toArray($item), 'user_id' => $userId]);
  313. }
  314. } catch (Exception $e) {
  315. Yii::$app->custom->logs(FormatHelper::exception($e, '【积分拓客】每日发放商品购买赠送冻结积分异常'), ['item' => ArrayHelper::toArray($item)]);
  316. }
  317. }
  318. }
  319. }
  320. }