>, * agent_edges: array, * agent_subtrees: array>, * platform_share_profit?: int, * } $aggregate * @return list bill ids */ public function generate(int $periodId, int $adminSiteId, array $aggregate): array { $billIds = []; $now = now(); $subtrees = $aggregate['agent_subtrees'] ?? []; foreach ($aggregate['players'] as $playerId => $row) { $net = (int) $row['net_amount']; $billIds[] = (int) DB::table('settlement_bills')->insertGetId([ 'settlement_period_id' => $periodId, 'bill_type' => 'player', 'owner_type' => 'player', 'owner_id' => $playerId, 'counterparty_type' => 'agent', 'counterparty_id' => (int) $row['agent_node_id'], 'gross_win_loss' => (int) $row['game_win_loss'], 'rebate_amount' => (int) $row['basic_rebate'] + (int) $row['extra_rebate'], 'adjustment_amount' => 0, 'platform_rounding_adjustment' => 0, 'net_amount' => $net, 'paid_amount' => 0, 'unpaid_amount' => abs($net), 'status' => 'pending_confirm', 'created_at' => $now, 'updated_at' => $now, ]); } foreach ($aggregate['agent_edges'] as $edge => $amount) { if ($amount === 0 || str_starts_with($edge, 'P_to_')) { continue; } $parsed = $this->parseEdge($edge); if ($parsed === null) { continue; } [$fromType, $fromId, $toType, $toId] = $parsed; $subtree = $subtrees[$fromId] ?? null; $billIds[] = (int) DB::table('settlement_bills')->insertGetId([ 'settlement_period_id' => $periodId, 'bill_type' => 'agent', 'owner_type' => $fromType, 'owner_id' => $fromId, 'counterparty_type' => $toType, 'counterparty_id' => $toId, 'gross_win_loss' => (int) ($subtree['gross_win_loss'] ?? 0), 'rebate_amount' => (int) ($subtree['basic_rebate'] ?? 0) + (int) ($subtree['extra_rebate'] ?? 0), 'adjustment_amount' => 0, 'platform_rounding_adjustment' => 0, 'net_amount' => $amount, 'paid_amount' => 0, 'unpaid_amount' => $amount, 'status' => 'pending_confirm', 'meta_json' => json_encode([ 'edge' => $edge, 'share_profit' => (int) ($subtree['share_profit'] ?? 0), 'player_count' => (int) ($subtree['player_count'] ?? 0), 'platform_share_profit' => $toType === 'platform' ? (int) ($aggregate['platform_share_profit'] ?? 0) : null, ]), 'created_at' => $now, 'updated_at' => $now, ]); } return $billIds; } /** * @return array{0: string, 1: int, 2: string, 3: int}|null */ private function parseEdge(string $edge): ?array { if (preg_match('/^P_to_(.+)$/', $edge, $m)) { $agent = AgentNode::query()->where('code', $m[1])->first(); if ($agent === null) { return null; } return ['agent', (int) $agent->id, 'player', 0]; } if (preg_match('/^(.+)_to_platform$/', $edge, $m)) { $agent = AgentNode::query()->where('code', $m[1])->first(); if ($agent === null) { return null; } return ['agent', (int) $agent->id, 'platform', 0]; } if (preg_match('/^(.+)_to_(.+)$/', $edge, $m)) { $from = AgentNode::query()->where('code', $m[1])->first(); $to = AgentNode::query()->where('code', $m[2])->first(); if ($from === null || $to === null) { return null; } return ['agent', (int) $from->id, 'agent', (int) $to->id]; } return null; } }