| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256 |
- <?php
- namespace App\Module\Promotion\Logics;
- use App\Module\Promotion\Enums\PROFIT_SOURCE_TYPE;
- use App\Module\Promotion\Enums\REFERRAL_LEVEL;
- use App\Module\Promotion\Models\PromotionProfit;
- use App\Module\Promotion\Models\PromotionProfitRule;
- use Illuminate\Support\Facades\Log;
- /**
- * 团队收益逻辑类
- *
- * 处理团队收益的核心业务逻辑,包括计算收益分成、记录收益、
- * 获取收益规则等功能。该类仅供内部使用,不对外提供服务。
- */
- class PromotionProfitLogic
- {
- /**
- * @var ReferralLogic
- */
- protected $referralLogic;
- /**
- * @var TalentLogic
- */
- protected $talentLogic;
- /**
- * 构造函数
- *
- * @param ReferralLogic $referralLogic
- * @param TalentLogic $talentLogic
- */
- public function __construct(ReferralLogic $referralLogic, TalentLogic $talentLogic)
- {
- $this->referralLogic = $referralLogic;
- $this->talentLogic = $talentLogic;
- }
- /**
- * 计算并记录团队收益分成
- *
- * @param int $userId 产生收益的用户ID
- * @param string $sourceType 收益来源类型
- * @param int $sourceId 收益来源ID
- * @param int $itemId 物品ID
- * @param int $amount 收益数量
- * @return bool
- */
- public function calculateAndRecordProfit(int $userId, string $sourceType, int $sourceId, int $itemId, int $amount): bool
- {
- try {
- // 获取收益分成规则
- $rule = $this->getProfitRule($sourceType);
- if (!$rule || !$rule->isActive()) {
- Log::info("收益分成规则不存在或未激活: {$sourceType}");
- return false;
- }
- // 检查收益是否满足最小数量要求
- $minAmount = $rule->getRuleAttribute('min_amount', 0);
- if ($amount < $minAmount) {
- Log::info("收益数量不满足最小要求: {$amount} < {$minAmount}");
- return false;
- }
- // 检查收益是否超过最大数量限制
- $maxAmount = $rule->getRuleAttribute('max_amount', PHP_INT_MAX);
- if ($amount > $maxAmount) {
- $amount = $maxAmount;
- Log::info("收益数量超过最大限制,已调整为: {$maxAmount}");
- }
- // 检查物品是否在排除列表中
- $excludedItems = $rule->getRuleAttribute('excluded_items', []);
- if (in_array($itemId, $excludedItems)) {
- Log::info("物品在排除列表中: {$itemId}");
- return false;
- }
- // 获取用户的所有上级
- $referrers = $this->referralLogic->getAllReferrers($userId, $rule->max_indirect_level);
- if (empty($referrers)) {
- Log::info("用户没有上级: {$userId}");
- return true;
- }
- // 检查事务是否已开启
- \UCore\Db\Helper::check_tr();
- // 记录收益分成
- $success = true;
- foreach ($referrers as $referrer) {
- $referrerId = $referrer['user_id'];
- $level = $referrer['level'];
- $depth = $referrer['depth'];
- // 计算分成比例
- $profitRate = $this->calculateProfitRate($level, $depth, $rule);
- // 计算分成数量
- $profitAmount = (int)($amount * $profitRate);
- if ($profitAmount <= 0) {
- continue;
- }
- // 记录收益
- $profit = new PromotionProfit();
- $profit->user_id = $referrerId;
- $profit->promotion_member_id = $userId;
- $profit->source_id = $sourceId;
- $profit->source_type = $sourceType;
- $profit->item_id = $itemId;
- $profit->profit_amount = $profitAmount;
- $profit->profit_rate = $profitRate;
- $profit->relation_type = $level;
- if (!$profit->save()) {
- $success = false;
- Log::error("记录收益分成失败: 用户 {$referrerId}, 来源 {$sourceType}, 数量 {$profitAmount}");
- }
- }
- return $success;
- } catch (\Exception $e) {
- Log::error("计算并记录团队收益分成失败: " . $e->getMessage());
- return false;
- }
- }
- /**
- * 计算分成比例
- *
- * @param int $level 关系层级
- * @param int $depth 层级深度
- * @param PromotionProfitRule $rule 分成规则
- * @return float
- */
- private function calculateProfitRate(int $level, int $depth, PromotionProfitRule $rule): float
- {
- // 直推关系
- if ($level == REFERRAL_LEVEL::DIRECT) {
- return $rule->direct_profit_rate;
- }
- // 间推关系
- if ($level == REFERRAL_LEVEL::INDIRECT) {
- // 获取用户的达人等级
- $talent = $this->talentLogic->getUserTalent($depth);
- if (!$talent || $talent->talent_level == 0) {
- return 0.0;
- }
- // 获取达人等级对应的分成比例
- $profitRate = $this->talentLogic->getTalentProfitRate($talent->talent_level);
- // 应用特殊规则
- $specialRates = $rule->getRuleAttribute('special_rates', []);
- foreach ($specialRates as $specialRate) {
- if (isset($specialRate['talent_level']) && $specialRate['talent_level'] == $talent->talent_level) {
- if (isset($specialRate['bonus_rate'])) {
- $profitRate += $specialRate['bonus_rate'];
- }
- }
- }
- return $profitRate;
- }
- return 0.0;
- }
- /**
- * 获取收益分成规则
- *
- * @param string $sourceType 收益来源类型
- * @return PromotionProfitRule|null
- */
- public function getProfitRule(string $sourceType): ?PromotionProfitRule
- {
- return PromotionProfitRule::where('source_type', $sourceType)
- ->where('status', 1)
- ->first();
- }
- /**
- * 获取用户的团队收益记录
- *
- * @param int $userId 用户ID
- * @param string|null $sourceType 收益来源类型
- * @param int $page 页码
- * @param int $pageSize 每页数量
- * @return array
- */
- public function getUserProfits(int $userId, ?string $sourceType = null, int $page = 1, int $pageSize = 20): array
- {
- $query = PromotionProfit::where('user_id', $userId);
- if ($sourceType) {
- $query->where('source_type', $sourceType);
- }
- $total = $query->count();
- $profits = $query->orderBy('created_at', 'desc')
- ->offset(($page - 1) * $pageSize)
- ->limit($pageSize)
- ->with(['promotionMember', 'item'])
- ->get();
- return [
- 'total' => $total,
- 'page' => $page,
- 'page_size' => $pageSize,
- 'total_pages' => ceil($total / $pageSize),
- 'profits' => $profits
- ];
- }
- /**
- * 统计用户的团队收益
- *
- * @param int $userId 用户ID
- * @param string|null $sourceType 收益来源类型
- * @param int|null $itemId 物品ID
- * @return array
- */
- public function sumUserProfits(int $userId, ?string $sourceType = null, ?int $itemId = null): array
- {
- $query = PromotionProfit::where('user_id', $userId);
- if ($sourceType) {
- $query->where('source_type', $sourceType);
- }
- if ($itemId) {
- $query->where('item_id', $itemId);
- }
- $directSum = (clone $query)->where('relation_type', REFERRAL_LEVEL::DIRECT)->sum('profit_amount');
- $indirectSum = (clone $query)->where('relation_type', REFERRAL_LEVEL::INDIRECT)->sum('profit_amount');
- $totalSum = $directSum + $indirectSum;
- return [
- 'direct_profit' => $directSum,
- 'indirect_profit' => $indirectSum,
- 'total_profit' => $totalSum
- ];
- }
- }
|