attributes->get('lottery_player'); $perPage = $this->perPage($request, 'per_page', 10, 50); $page = $this->page($request); $drawNo = $request->query('draw_no'); $statusInput = $request->query('status', []); if (is_string($statusInput)) { $statusInput = [$statusInput]; } $statusValues = is_array($statusInput) ? array_values(array_filter(array_map( fn ($status) => is_string($status) ? trim($status) : '', $statusInput, ))) : []; $number = trim((string) $request->query('number', '')); $startDate = $this->normalizeDate((string) $request->query('start_date', '')); $endDate = $this->normalizeDate((string) $request->query('end_date', '')); $query = TicketItem::query() ->where('ticket_items.player_id', $player->id) ->with([ 'draw:id,draw_no,business_date', 'order:id,order_no,currency_code,status,created_at', ]) ->orderByDesc('ticket_items.id'); if (is_string($drawNo) && $drawNo !== '') { $drawNo = trim($drawNo); $query->whereHas('draw', fn ($q) => $q->where('draw_no', $drawNo)); } if ($statusValues !== []) { $query->whereIn('ticket_items.status', $statusValues); } if ($number !== '') { $query->where(function ($q) use ($number): void { $q->where('ticket_items.original_number', 'like', '%'.$number.'%') ->orWhere('ticket_items.normalized_number', 'like', '%'.$number.'%') ->orWhere('ticket_items.ticket_no', 'like', '%'.$number.'%'); }); } if ($startDate !== null) { $fromUtc = $this->scheduleDateStartUtc($startDate); $query->whereHas('order', fn ($q) => $q->where('created_at', '>=', $fromUtc)); } if ($endDate !== null) { $toUtc = $this->scheduleDateEndUtc($endDate); $query->whereHas('order', fn ($q) => $q->where('created_at', '<=', $toUtc)); } $paginator = $query->paginate(perPage: $perPage, page: $page); $items = collect($paginator->items())->map(function (TicketItem $row): array { $totalBet = (int) $row->total_bet_amount; $actualDeduct = (int) $row->actual_deduct_amount; $winAmount = (int) $row->win_amount; $jackpotWin = (int) $row->jackpot_win_amount; return [ 'ticket_no' => $row->ticket_no, 'order_no' => $row->order?->order_no, 'order_status' => $row->order?->status, 'draw_no' => $row->draw?->draw_no, 'currency_code' => $row->order?->currency_code, 'play_code' => $row->play_code, 'original_number' => $row->original_number, 'total_bet_amount' => $totalBet, 'total_bet_amount_formatted' => CurrencyFormatter::fromMinor($totalBet), 'actual_deduct_amount' => $actualDeduct, 'actual_deduct_amount_formatted' => CurrencyFormatter::fromMinor($actualDeduct), 'status' => $row->status, 'win_amount' => $winAmount, 'win_amount_formatted' => CurrencyFormatter::fromMinor($winAmount), 'jackpot_win_amount' => $jackpotWin, 'jackpot_win_amount_formatted' => CurrencyFormatter::fromMinor($jackpotWin), 'placed_at' => $row->order?->created_at?->toIso8601String(), 'updated_at' => $row->updated_at?->toIso8601String(), ]; })->values()->all(); return ApiResponse::success([ 'items' => $items, 'total' => $paginator->total(), 'page' => $paginator->currentPage(), 'per_page' => $paginator->perPage(), 'last_page' => $paginator->lastPage(), ]); } private function normalizeDate(string $value): ?string { $value = trim($value); if ($value === '' || ! preg_match('/^\d{4}-\d{2}-\d{2}$/', $value)) { return null; } return $value; } private function scheduleTimezone(): string { return (string) config('lottery.draw.timezone', 'UTC'); } private function scheduleDateStartUtc(string $ymd): Carbon { return Carbon::createFromFormat('Y-m-d', $ymd, $this->scheduleTimezone()) ->startOfDay() ->utc(); } private function scheduleDateEndUtc(string $ymd): Carbon { return Carbon::createFromFormat('Y-m-d', $ymd, $this->scheduleTimezone()) ->endOfDay() ->utc(); } }