, * chain_codes: list, * total_shares: array, * actual_shares: array, * rebate_rate: float, * extra_rebate_rate: float, * } */ public function buildForPlayer(Player $player, string $gameType = '*'): array { $agentNodeId = (int) $player->agent_node_id; if ($agentNodeId <= 0) { throw new \InvalidArgumentException('player_missing_agent'); } $pathIds = []; $chainCodes = []; $totalShares = []; $nodeId = $agentNodeId; while ($nodeId > 0) { $node = AgentNode::query()->find($nodeId); if ($node === null) { break; } array_unshift($pathIds, (int) $node->id); $profile = AgentProfile::query()->where('agent_node_id', $node->id)->first(); $code = (string) $node->code; $chainCodes[] = $code; $totalShares[$code] = (float) ($profile?->total_share_rate ?? 0); $nodeId = (int) ($node->parent_id ?? 0); } $orderedBottomUp = $chainCodes; $actual = $this->resolveActualShares($totalShares, $orderedBottomUp); $rebate = $this->resolvePlayerRebateRate((int) $player->id, $agentNodeId, $gameType); return [ 'agent_node_id' => $agentNodeId, 'agent_path' => $pathIds, 'chain_codes' => $orderedBottomUp, 'total_shares' => $totalShares, 'actual_shares' => $actual, 'rebate_rate' => $rebate['rebate_rate'], 'extra_rebate_rate' => $rebate['extra_rebate_rate'], ]; } /** * @param array $totalShares * @param list $orderedBottomUp * @return array */ private function resolveActualShares(array $totalShares, array $orderedBottomUp): array { $actual = []; $prev = 0.0; foreach ($orderedBottomUp as $code) { $total = (float) ($totalShares[$code] ?? 0); $actual[$code] = max(0, $total - $prev); $prev = $total; } $actual['platform'] = max(0, 100 - $prev); return $actual; } /** * @return array{rebate_rate: float, extra_rebate_rate: float} */ private function resolvePlayerRebateRate(int $playerId, int $agentNodeId, string $gameType = '*'): array { $gameType = trim($gameType) !== '' ? trim($gameType) : '*'; $row = DB::table('player_rebate_profiles') ->where('player_id', $playerId) ->where('game_type', $gameType) ->first(); if ($row === null && $gameType !== '*') { $row = DB::table('player_rebate_profiles') ->where('player_id', $playerId) ->where('game_type', '*') ->first(); } if ($row !== null && ! (bool) $row->inherit_from_agent) { return [ 'rebate_rate' => (float) $row->rebate_rate, 'extra_rebate_rate' => (float) $row->extra_rebate_rate, ]; } $profile = AgentProfile::query()->where('agent_node_id', $agentNodeId)->first(); return [ 'rebate_rate' => (float) ($profile?->default_player_rebate ?? 0), 'extra_rebate_rate' => 0.0, ]; } }