lotteryAdmin(); abort_if($admin === null, 401); $p = AdminApiList::readPaging($request); $drawNo = trim((string) $request->query('draw_no', '')); $status = trim((string) $request->query('status', '')); $agentNodeId = $request->integer('agent_node_id') ?: null; $q = Draw::query()->orderByDesc('draw_time')->orderByDesc('id'); if ($drawNo !== '') { $q->where('draw_no', 'like', '%'.$drawNo.'%'); } if ($status !== '') { $q->where('status', $status); } /** @var LengthAwarePaginator $paginator */ $paginator = $q->paginate($p['perPage'], ['*'], 'page', $p['page']); $statsByDrawId = $this->aggregateListStats( $paginator->getCollection()->pluck('id')->map(fn ($id) => (int) $id)->all(), $admin, $agentNodeId, ); return AdminApiList::jsonWith($paginator, fn (Draw $row) => $this->row($row, $statsByDrawId), [ 'schedule' => [ 'timezone' => LotterySettings::drawTimezone(), 'interval_minutes' => LotterySettings::drawIntervalMinutes(), 'betting_window_seconds' => LotterySettings::drawBettingWindowSeconds(), 'close_before_draw_seconds' => LotterySettings::drawCloseBeforeDrawSeconds(), ], ]); } /** * @param list $drawIds * @return array */ private function aggregateListStats(array $drawIds, AdminUser $admin, ?int $agentNodeId): array { if ($drawIds === []) { return []; } $betQuery = TicketOrder::query()->whereIn('draw_id', $drawIds); $this->scopeOrdersToVisiblePlayers($betQuery, $admin, $agentNodeId); $betByDraw = $betQuery ->groupBy('draw_id') ->selectRaw('draw_id, COALESCE(SUM(total_actual_deduct), 0) AS total_bet') ->pluck('total_bet', 'draw_id'); $payoutQuery = TicketItem::query()->whereIn('draw_id', $drawIds); $this->scopeTicketItemsToVisiblePlayers($payoutQuery, $admin, $agentNodeId); $payoutRows = $payoutQuery ->groupBy('draw_id') ->selectRaw( 'draw_id, COALESCE(SUM(win_amount), 0) AS win, COALESCE(SUM(jackpot_win_amount), 0) AS jackpot', ) ->get() ->keyBy('draw_id'); $stats = []; foreach ($drawIds as $drawId) { $bet = (int) ($betByDraw[$drawId] ?? $betByDraw[(string) $drawId] ?? 0); $payoutRow = $payoutRows->get($drawId) ?? $payoutRows->get((string) $drawId); $payout = (int) ($payoutRow->win ?? 0) + (int) ($payoutRow->jackpot ?? 0); $stats[$drawId] = [ 'total_bet_minor' => $bet, 'total_payout_minor' => $payout, 'profit_loss_minor' => $bet - $payout, ]; } return $stats; } /** * @param \Illuminate\Database\Eloquent\Builder $query */ private function scopeOrdersToVisiblePlayers($query, AdminUser $admin, ?int $agentNodeId): void { if ($admin->isSuperAdmin() && ($agentNodeId === null || $agentNodeId <= 0)) { return; } $query->whereHas('player', static function ($playerQuery) use ($admin, $agentNodeId): void { AdminSiteScope::applyPlayerFilters( $playerQuery, $admin, null, $agentNodeId !== null && $agentNodeId > 0 ? $agentNodeId : null, ); }); } /** * @param \Illuminate\Database\Eloquent\Builder $query */ private function scopeTicketItemsToVisiblePlayers($query, AdminUser $admin, ?int $agentNodeId): void { if ($admin->isSuperAdmin() && ($agentNodeId === null || $agentNodeId <= 0)) { return; } $query->whereHas('player', static function ($playerQuery) use ($admin, $agentNodeId): void { AdminSiteScope::applyPlayerFilters( $playerQuery, $admin, null, $agentNodeId !== null && $agentNodeId > 0 ? $agentNodeId : null, ); }); } /** * @param array $statsByDrawId * @return array */ private function row(Draw $draw, array $statsByDrawId): array { $stats = $statsByDrawId[(int) $draw->id] ?? [ 'total_bet_minor' => 0, 'total_payout_minor' => 0, 'profit_loss_minor' => 0, ]; return [ 'id' => (int) $draw->id, 'draw_no' => $draw->draw_no, 'business_date' => $draw->business_date instanceof Carbon ? $draw->business_date->format('Y-m-d') : (string) $draw->business_date, 'sequence_no' => (int) $draw->sequence_no, 'status' => $draw->status, 'start_time' => $draw->start_time?->toIso8601String(), 'close_time' => $draw->close_time?->toIso8601String(), 'draw_time' => $draw->draw_time?->toIso8601String(), 'cooling_end_time' => $draw->cooling_end_time?->toIso8601String(), 'result_source' => $draw->result_source, 'current_result_version' => (int) $draw->current_result_version, 'settle_version' => (int) $draw->settle_version, 'is_reopened' => (bool) $draw->is_reopened, 'total_bet_minor' => $stats['total_bet_minor'], 'total_payout_minor' => $stats['total_payout_minor'], 'profit_loss_minor' => $stats['profit_loss_minor'], 'updated_at' => $draw->updated_at?->toIso8601String(), ]; } }