lotteryAdmin(); abort_if($admin === null, 401); $ticketNo = trim($ticket_no); $scope = AdminScopePolicy::resolveContext($request, $admin); $query = TicketItem::query() ->where('ticket_no', $ticketNo) ->with([ 'combinations', 'draw:id,draw_no,business_date', 'order:id,order_no,currency_code,created_at,status', 'player:id,site_code,site_player_id,username,nickname,agent_node_id,funding_mode', 'player.agentNode:id,code,name', ]); AdminScopePolicy::applyViaPlayerRelationWithContext($query, $scope, 'player'); $item = $query->first(); if ($item === null) { return ApiResponse::error( trans('api.not_found', [], $request->lotteryLocale()), ErrorCode::NotFound->value, null, 404, ); } $totalBet = (int) $item->total_bet_amount; $actualDeduct = (int) $item->actual_deduct_amount; return ApiResponse::success([ 'id' => (int) $item->id, 'ticket_no' => $item->ticket_no, 'order_no' => $item->order?->order_no, 'order_status' => $item->order?->status, 'draw_id' => (int) $item->draw_id, 'draw_no' => $item->draw?->draw_no, 'currency_code' => $item->order?->currency_code, 'provider_code' => $item->provider_code, 'provider_name' => $item->provider_name, 'player_id' => $item->player_id, 'site_code' => $item->player?->site_code, 'site_player_id' => $item->player?->site_player_id, 'username' => $item->player?->username, 'nickname' => $item->player?->nickname, 'funding_mode' => $item->player?->funding_mode, 'agent_node_id' => $item->player?->agent_node_id, 'agent_code' => $item->player?->agentNode?->code, 'agent_name' => $item->player?->agentNode?->name, 'play_code' => $item->play_code, 'dimension' => $item->dimension, 'digit_slot' => $item->digit_slot, 'original_number' => $item->original_number, 'normalized_number' => $item->normalized_number, 'combination_count' => (int) $item->combination_count, 'unit_bet_amount' => (int) $item->unit_bet_amount, 'total_bet_amount_minor' => $totalBet, 'total_bet_amount_formatted' => CurrencyFormatter::fromMinor($totalBet), 'actual_deduct_amount_minor' => $actualDeduct, 'actual_deduct_amount_formatted' => CurrencyFormatter::fromMinor($actualDeduct), 'risk_locked_amount' => (int) $item->risk_locked_amount, 'odds_snapshot_json' => $item->odds_snapshot_json, 'status' => $item->status, 'fail_reason_code' => $item->fail_reason_code, 'fail_reason_text' => $item->fail_reason_text, 'win_amount_minor' => (int) $item->win_amount, 'win_amount_formatted' => CurrencyFormatter::fromMinor((int) $item->win_amount), 'placed_at' => $item->order?->created_at?->toIso8601String(), 'updated_at' => $item->updated_at?->toIso8601String(), 'combinations' => $item->combinations ->sortBy('combination_no') ->values() ->map(fn ($combo): array => [ 'combination_no' => (int) $combo->combination_no, 'number_4d' => (string) $combo->number_4d, 'bet_amount' => (int) $combo->bet_amount, 'estimated_payout' => (int) $combo->estimated_payout, ]) ->all(), ]); } }