|null */ public function build(AdminUser $admin, AdminScopeContext $scope): ?array { if (! $admin->hasPermissionCode('dashboard.view')) { return null; } $site = $this->resolvePrimarySite($admin); if ($site === null) { return null; } $siteId = (int) $site->id; $siteCode = (string) $site->code; $agentNodeIds = AgentNode::query() ->where('admin_site_id', $siteId) ->pluck('id') ->map(static fn ($id): int => (int) $id) ->all(); $playerCount = (int) Player::query()->where('site_code', $siteCode)->count(); $today = now()->toDateString(); $sevenDayFrom = now()->subDays(6)->toDateString(); $scoped = AdminScopeContextResolver::fromValues( $admin, requestedSiteCode: $siteCode, ); $todayTotals = $this->reportQuery->periodFinanceTotals($today, $today, $scoped); $sevenDayTotals = $this->reportQuery->periodFinanceTotals($sevenDayFrom, $today, $scoped); $currencyCode = $this->reportQuery->resolvePeriodCurrencyCode($today, $today, $scoped) ?? $this->reportQuery->resolvePeriodCurrencyCode($sevenDayFrom, $today, $scoped); $todayActivity = $this->todayActivityStats($siteCode, $today); $pendingBills = $this->pendingBillStats($siteId); $topAgentToday = $this->topAgentToday($scoped, $today); return [ 'admin_site_id' => $siteId, 'site_code' => $siteCode, 'site_name' => (string) $site->name, 'agent_count' => count($agentNodeIds), 'player_count' => $playerCount, 'active_player_count_today' => $todayActivity['player_count'], 'bet_order_count_today' => $todayActivity['order_count'], 'today_bet_minor' => $todayTotals['total_bet_minor'], 'today_payout_minor' => $todayTotals['total_payout_minor'], 'today_profit_minor' => $todayTotals['approx_house_gross_minor'], 'seven_day_bet_minor' => $sevenDayTotals['total_bet_minor'], 'seven_day_payout_minor' => $sevenDayTotals['total_payout_minor'], 'seven_day_profit_minor' => $sevenDayTotals['approx_house_gross_minor'], 'profit_scope' => 'house_gross', 'currency_code' => $currencyCode, 'pending_bill_count' => $pendingBills['count'], 'pending_unpaid_minor' => $pendingBills['unpaid_minor'], 'latest_bet_at' => $todayActivity['latest_bet_at'], 'top_agent_today' => $topAgentToday, ]; } private function resolvePrimarySite(AdminUser $admin): ?AdminSite { $siteIds = $admin->accessibleAdminSiteIds(); if ($siteIds === null || $siteIds === []) { return null; } return AdminSite::query() ->where('id', (int) $siteIds[0]) ->first(); } /** * @return array{player_count: int, order_count: int, latest_bet_at: ?string} */ private function todayActivityStats(string $siteCode, string $today): array { $base = DB::table('ticket_orders as o') ->join('players as p', 'p.id', '=', 'o.player_id') ->where('p.site_code', $siteCode) ->whereDate('o.created_at', $today); $latestBetAt = (clone $base)->max('o.created_at'); return [ 'player_count' => (int) (clone $base)->distinct('o.player_id')->count('o.player_id'), 'order_count' => (int) (clone $base)->count(), 'latest_bet_at' => $latestBetAt !== null ? Carbon::parse((string) $latestBetAt)->toIso8601String() : null, ]; } /** * @return array{count: int, unpaid_minor: int} */ private function pendingBillStats(int $siteId): array { $query = DB::table('settlement_bills as sb') ->join('settlement_periods as sp', 'sp.id', '=', 'sb.settlement_period_id') ->where('sp.admin_site_id', $siteId) ->whereIn('sb.status', ['pending', 'pending_confirm', 'partial']); return [ 'count' => (int) $query->count(), 'unpaid_minor' => (int) $query->sum('sb.unpaid_amount'), ]; } /** * @return array|null */ private function topAgentToday(AdminScopeContext $scope, string $today): ?array { $rows = $this->reportQuery->agentRankingRows($today, $today, null, 1, $scope); return $rows[0] ?? null; } }