UrsRewardDistributionService.php 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. <?php
  2. namespace App\Module\UrsPromotion\Services;
  3. use App\Module\UrsPromotion\Dtos\UrsProfitDto;
  4. use App\Module\UrsPromotion\Models\UrsUserMapping;
  5. use App\Module\UrsPromotion\Models\UrsUserReferral;
  6. use App\Module\UrsPromotion\Models\UrsUserTalent;
  7. use App\Module\UrsPromotion\Models\UrsProfit;
  8. /**
  9. * URS奖励分发服务
  10. *
  11. * 实现奖励发放逻辑:
  12. * 1. 根据URS用户ID查找上级关系链
  13. * 2. 检查每个上级是否已进入农场
  14. * 3. 如果上级未进入农场则跳过,继续处理上上级
  15. * 4. 记录奖励分发结果
  16. */
  17. class UrsRewardDistributionService
  18. {
  19. /**
  20. * 分发推广奖励
  21. *
  22. * @param int $ursUserId 产生收益的URS用户ID
  23. * @param int $sourceId 收益来源ID
  24. * @param string $sourceType 收益来源类型
  25. * @param string $profitType 收益类型
  26. * @param float $originalAmount 原始收益金额
  27. * @param array $rewardConfig 奖励配置 [level => rate]
  28. * @return array 分发结果
  29. */
  30. public static function distributeReward(
  31. int $ursUserId,
  32. int $sourceId,
  33. string $sourceType,
  34. string $profitType,
  35. float $originalAmount,
  36. array $rewardConfig
  37. ): array
  38. {
  39. $results = [];
  40. // 获取上级关系链
  41. $referralChain = self::getReferralChain($ursUserId, count($rewardConfig));
  42. $level = 1;
  43. foreach ($referralChain as $referrerUrsUserId) {
  44. if (!isset($rewardConfig[$level])) {
  45. break; // 超出配置层级
  46. }
  47. $rate = $rewardConfig[$level];
  48. $profitAmount = $originalAmount * $rate;
  49. // 检查推荐人是否已进入农场
  50. $farmUserId = UrsUserMapping::getFarmUserIdByUrsUserId($referrerUrsUserId);
  51. if ($farmUserId === 0) {
  52. // 推荐人未进入农场,记录跳过状态
  53. $results[] = self::recordSkippedReward(
  54. $referrerUrsUserId,
  55. $ursUserId,
  56. $sourceId,
  57. $sourceType,
  58. $profitType,
  59. $level,
  60. $originalAmount,
  61. $profitAmount,
  62. $rate
  63. );
  64. } else {
  65. // 推荐人已进入农场,记录正常奖励
  66. $results[] = self::recordNormalReward(
  67. $referrerUrsUserId,
  68. $farmUserId,
  69. $ursUserId,
  70. $sourceId,
  71. $sourceType,
  72. $profitType,
  73. $level,
  74. $originalAmount,
  75. $profitAmount,
  76. $rate
  77. );
  78. }
  79. $level++;
  80. }
  81. return $results;
  82. }
  83. /**
  84. * 获取推荐关系链
  85. *
  86. * @param int $ursUserId URS用户ID
  87. * @param int $maxLevels 最大层级数
  88. * @return array URS用户ID数组,按层级排序
  89. */
  90. private static function getReferralChain(int $ursUserId, int $maxLevels): array
  91. {
  92. return UrsReferralService::getReferralChain($ursUserId, $maxLevels);
  93. }
  94. /**
  95. * 记录跳过的奖励
  96. */
  97. private static function recordSkippedReward(
  98. $ursUserId,
  99. int $promotionMemberUrsUserId,
  100. int $sourceId,
  101. string $sourceType,
  102. string $profitType,
  103. int $relationLevel,
  104. float $originalAmount,
  105. float $profitAmount,
  106. float $profitRate
  107. ): array
  108. {
  109. $framUserId = UrsUserMappingService::getFarmUserId($ursUserId);
  110. $talent = UrsUserTalent::where('user_id', $framUserId)->first();
  111. $talentLevel = $talent ? $talent->talent_level : 0;
  112. $profit = UrsProfit::create([
  113. 'urs_user_id' => $ursUserId,
  114. 'urs_promotion_member_id' => $promotionMemberUrsUserId,
  115. 'source_id' => $sourceId,
  116. 'source_type' => $sourceType,
  117. 'profit_type' => $profitType,
  118. 'relation_level' => $relationLevel,
  119. 'original_amount' => $originalAmount,
  120. 'profit_amount' => $profitAmount,
  121. 'profit_rate' => $profitRate,
  122. 'talent_level' => $talentLevel,
  123. 'farm_user_id' => $framUserId,
  124. 'status' => UrsProfit::STATUS_SKIPPED,
  125. ]);
  126. return [
  127. 'urs_user_id' => $ursUserId,
  128. 'farm_user_id' => null,
  129. 'relation_level' => $relationLevel,
  130. 'profit_amount' => $profitAmount,
  131. 'status' => 'skipped',
  132. 'reason' => '用户未进入农场',
  133. 'profit_id' => $profit->id,
  134. ];
  135. }
  136. /**
  137. * 记录正常奖励
  138. */
  139. private static function recordNormalReward(
  140. int $ursUserId,
  141. int $farmUserId,
  142. int $promotionMemberUrsUserId,
  143. int $sourceId,
  144. string $sourceType,
  145. string $profitType,
  146. int $relationLevel,
  147. float $originalAmount,
  148. float $profitAmount,
  149. float $profitRate
  150. ): array
  151. {
  152. $framUserId = UrsUserMappingService::getFarmUserId($ursUserId);
  153. $talent = UrsUserTalent::where('user_id', $framUserId)->first();
  154. $talentLevel = $talent ? $talent->talent_level : 0;
  155. $profit = UrsProfit::create([
  156. 'urs_user_id' => $ursUserId,
  157. 'urs_promotion_member_id' => $promotionMemberUrsUserId,
  158. 'source_id' => $sourceId,
  159. 'source_type' => $sourceType,
  160. 'profit_type' => $profitType,
  161. 'relation_level' => $relationLevel,
  162. 'original_amount' => $originalAmount,
  163. 'profit_amount' => $profitAmount,
  164. 'profit_rate' => $profitRate,
  165. 'talent_level' => $talentLevel,
  166. 'farm_user_id' => $farmUserId,
  167. 'status' => UrsProfit::STATUS_NORMAL,
  168. ]);
  169. return [
  170. 'urs_user_id' => $ursUserId,
  171. 'farm_user_id' => $farmUserId,
  172. 'relation_level' => $relationLevel,
  173. 'profit_amount' => $profitAmount,
  174. 'status' => 'success',
  175. 'reason' => '奖励发放成功',
  176. 'profit_id' => $profit->id,
  177. ];
  178. }
  179. /**
  180. * 获取用户的奖励统计
  181. *
  182. * @param int $ursUserId URS用户ID
  183. * @param string|null $profitType 收益类型筛选
  184. * @return array
  185. */
  186. public static function getUserRewardStats(int $ursUserId, ?string $profitType = null): array
  187. {
  188. $query = UrsProfit::where('urs_user_id', $ursUserId);
  189. if ($profitType) {
  190. $query->where('profit_type', $profitType);
  191. }
  192. $stats = [
  193. 'total_amount' => $query->sum('profit_amount'),
  194. 'normal_count' => $query->where('status', UrsProfit::STATUS_NORMAL)->count(),
  195. 'skipped_count' => $query->where('status', UrsProfit::STATUS_SKIPPED)->count(),
  196. 'cancelled_count' => $query->where('status', UrsProfit::STATUS_CANCELLED)->count(),
  197. ];
  198. return $stats;
  199. }
  200. /**
  201. * 获取跳过的奖励列表
  202. *
  203. * @param int $ursUserId URS用户ID
  204. * @return UrsProfitDto[]
  205. */
  206. public static function getSkippedRewards(int $ursUserId): array
  207. {
  208. $profits = UrsProfit::where('urs_user_id', $ursUserId)
  209. ->where('status', UrsProfit::STATUS_SKIPPED)
  210. ->orderBy('created_at', 'desc')
  211. ->get();
  212. return $profits->map(function ($profit) {
  213. return UrsProfitDto::fromModel($profit);
  214. })->toArray();
  215. }
  216. }