partnerSiteConfigResolver->resolveForPlayer($player); return $this->post( $config->walletDebitPath, $player, $currencyCode, $amountMinor, $idempotentKey, $config, ); } public function creditMainForLotteryWithdraw( Player $player, string $currencyCode, int $amountMinor, string $idempotentKey, ): MainSiteWalletResult { $config = $this->partnerSiteConfigResolver->resolveForPlayer($player); return $this->post( $config->walletCreditPath, $player, $currencyCode, $amountMinor, $idempotentKey, $config, ); } private function post( string $path, Player $player, string $currencyCode, int $amountMinor, string $idempotentKey, \App\Services\Integration\PartnerSiteConfig $config, ): MainSiteWalletResult { if (! $config->hasWalletApi()) { return MainSiteWalletResult::success(null, ['stub' => true, 'reason' => 'wallet_api_not_configured'], [ 'site_code' => $player->site_code, 'site_player_id' => $player->site_player_id, 'player_id' => $player->id, 'currency_code' => $currencyCode, 'amount_minor' => $amountMinor, 'idempotent_key' => $idempotentKey, '_meta' => ['stub' => true], ]); } $base = rtrim((string) $config->walletApiUrl, '/'); $url = $base.'/'.ltrim($path, '/'); $timeout = $config->walletTimeoutSeconds; $apiKey = $config->walletApiKey; $requestBody = [ 'site_code' => $player->site_code, 'site_player_id' => $player->site_player_id, 'player_id' => $player->id, 'currency_code' => $currencyCode, 'amount_minor' => $amountMinor, 'idempotent_key' => $idempotentKey, ]; $requestSnapshot = array_merge($requestBody, [ '_meta' => [ 'method' => 'POST', 'path' => '/'.ltrim($path, '/'), ], ]); $headers = []; if (is_string($apiKey) && $apiKey !== '') { $headers['Authorization'] = 'Bearer '.$apiKey; } try { $response = Http::withHeaders($headers) ->timeout($timeout) ->acceptJson() ->asJson() ->post($url, $requestBody); } catch (\Throwable $e) { return MainSiteWalletResult::failure( $e->getMessage(), null, self::isUncertainTransportFailure($e), $requestSnapshot, ); } $payload = $response->json(); if (! is_array($payload)) { $payload = ['raw' => $response->body()]; } $status = $response->status(); if ($status === 408 || $status === 504) { return MainSiteWalletResult::failure( 'HTTP '.$status, $payload, true, $requestSnapshot, ); } if (! $response->successful()) { return MainSiteWalletResult::failure( is_string(data_get($payload, 'message')) ? (string) data_get($payload, 'message') : ('HTTP '.$status), $payload, false, $requestSnapshot, ); } $ok = (bool) data_get($payload, 'success', true); if (! $ok) { return MainSiteWalletResult::failure( is_string(data_get($payload, 'message')) ? (string) data_get($payload, 'message') : 'main_site_rejected', $payload, false, $requestSnapshot, ); } $ref = data_get($payload, 'external_ref_no') ?? data_get($payload, 'data.external_ref_no') ?? data_get($payload, 'ref'); return MainSiteWalletResult::success(is_string($ref) ? $ref : null, $payload, $requestSnapshot); } private static function isUncertainTransportFailure(\Throwable $e): bool { if ($e instanceof ConnectException) { return true; } $msg = strtolower($e->getMessage()); return str_contains($msg, 'curl error 28') || str_contains($msg, 'connection timed out') || str_contains($msg, 'timed out') || str_contains($msg, 'operation timed out'); } }