role), ['admin', 'owner']), 403); $settings = $this->deposits->getSettings(); return Inertia::render('Admin/PaymentsSettings', [ 'settings' => $settings, 'defaults' => [ 'commonCurrencies' => ['BTC','ETH','LTC','SOL','USDT_ERC20','USDT_TRC20','BCH','DOGE'], 'modes' => ['live','sandbox'], 'addressModes' => ['per_payment','per_user'], ], ]); } /** * POST /admin/payments/settings */ public function save(Request $request) { $user = Auth::user(); abort_unless($user && in_array(strtolower((string) $user->role), ['admin', 'owner']), 403); $data = $request->validate([ 'mode' => ['required','in:live,sandbox'], 'api_key' => ['nullable','string','max:200'], 'ipn_secret' => ['nullable','string','max:200'], 'enabled_currencies' => ['required','array','min:1'], 'enabled_currencies.*' => ['string','max:32'], 'global_min_usd' => ['required','numeric','min:0'], 'global_max_usd' => ['required','numeric','gt:global_min_usd'], 'btx_per_usd' => ['required','numeric','min:0.00000001'], 'per_currency_overrides' => ['sometimes','array'], 'per_currency_overrides.*.min_usd' => ['nullable','numeric','min:0'], 'per_currency_overrides.*.max_usd' => ['nullable','numeric'], 'per_currency_overrides.*.btx_per_usd' => ['nullable','numeric','min:0.00000001'], 'success_url' => ['required','string','max:255'], 'cancel_url' => ['required','string','max:255'], 'address_mode' => ['required','in:per_payment,per_user'], ]); // Normalize overrides structure as map keyed by currency $overrides = []; if (!empty($data['per_currency_overrides']) && is_array($data['per_currency_overrides'])) { foreach ($data['per_currency_overrides'] as $cur => $vals) { if (is_array($vals)) { $entry = []; if (array_key_exists('min_usd', $vals) && $vals['min_usd'] !== null) $entry['min_usd'] = (float) $vals['min_usd']; if (array_key_exists('max_usd', $vals) && $vals['max_usd'] !== null) $entry['max_usd'] = (float) $vals['max_usd']; if (array_key_exists('btx_per_usd', $vals) && $vals['btx_per_usd'] !== null) $entry['btx_per_usd'] = (float) $vals['btx_per_usd']; if (!empty($entry)) { $overrides[strtoupper($cur)] = $entry; } } } } // Preserve existing api_key/ipn_secret if not re-submitted (masked fields) $existing = AppSetting::get('payments.nowpayments', []); $apiKey = $data['api_key'] ?? null; $ipnSecret = $data['ipn_secret'] ?? null; $payload = [ 'mode' => $data['mode'], 'api_key' => $apiKey ?: ($existing['api_key'] ?? ''), 'ipn_secret' => $ipnSecret ?: ($existing['ipn_secret'] ?? ''), 'enabled_currencies' => array_values(array_map('strtoupper', $data['enabled_currencies'])), 'global_min_usd' => (float) $data['global_min_usd'], 'global_max_usd' => (float) $data['global_max_usd'], 'btx_per_usd' => (float) $data['btx_per_usd'], 'per_currency_overrides' => $overrides, 'success_url' => (string) $data['success_url'], 'cancel_url' => (string) $data['cancel_url'], 'address_mode' => (string) $data['address_mode'], ]; AppSetting::put('payments.nowpayments', $payload); return back()->with('success', 'Payment settings saved.'); } /** * POST /admin/payments/test */ public function test(Request $request) { $user = Auth::user(); abort_unless($user && in_array(strtolower((string) $user->role), ['admin', 'owner']), 403); $data = $request->validate(['api_key' => 'required|string|max:200']); try { $res = Http::timeout(8)->withHeaders([ 'x-api-key' => $data['api_key'], 'Accept' => 'application/json', ])->get('https://api.nowpayments.io/v1/status'); if ($res->ok()) { return response()->json(['ok' => true, 'message' => 'Verbindung erfolgreich! NOWPayments API erreichbar.']); } return response()->json(['ok' => false, 'message' => 'API antwortet mit Status ' . $res->status() . '. API Key prüfen.'], 422); } catch (\Throwable $e) { return response()->json(['ok' => false, 'message' => 'Verbindung fehlgeschlagen: ' . $e->getMessage()], 422); } } }