$package, 'packageOptions' => $packages, 'stripePublishableKey' => config('services.stripe.key'), 'paypalClientId' => config('services.paypal.client_id'), 'privacyHtml' => view('legal.datenschutz-partial')->render(), 'auth' => [ 'user' => Auth::user(), ], ]); } public function register(Request $request) { $validator = Validator::make($request->all(), [ 'email' => 'required|email|unique:users,email', 'password' => ['required', 'confirmed', Password::defaults()], 'package_id' => 'required|exists:packages,id', 'terms' => 'required|accepted', ]); if ($validator->fails()) { return response()->json([ 'errors' => $validator->errors(), ], 422); } $package = Package::findOrFail($request->package_id); $validated = $validator->validated(); DB::transaction(function () use ($request, $package, $validated) { // User erstellen $user = User::create([ 'email' => $request->email, 'password' => Hash::make($request->password), 'pending_purchase' => true, ]); // Tenant erstellen $tenant = Tenant::create([ 'user_id' => $user->id, 'name' => $validated['first_name'] . ' ' . $validated['last_name'], 'slug' => Str::slug($validated['first_name'] . ' ' . $validated['last_name'] . '-' . now()->timestamp), 'email' => $validated['email'], 'is_active' => true, 'is_suspended' => false, 'event_credits_balance' => 0, 'subscription_tier' => 'free', 'subscription_expires_at' => null, 'settings' => json_encode([ 'branding' => [ 'logo_url' => null, 'primary_color' => '#3B82F6', 'secondary_color' => '#1F2937', 'font_family' => 'Inter, sans-serif', ], 'features' => [ 'photo_likes_enabled' => false, 'event_checklist' => false, 'custom_domain' => false, 'advanced_analytics' => false, ], 'custom_domain' => null, 'contact_email' => $validated['email'], 'event_default_type' => 'general', ]), ]); // Package zuweisen $tenant->packages()->attach($package->id, [ 'purchased_at' => now(), 'expires_at' => $package->is_free ? null : now()->addYear(), 'is_active' => $package->is_free, // Kostenlose Pakete sofort aktivieren ]); // E-Mail-Verifizierung senden $user->sendEmailVerificationNotification(); // Willkommens-E-Mail senden Mail::to($user)->queue(new Welcome($user)); }); return response()->json([ 'message' => 'Registrierung erfolgreich. Bitte überprüfen Sie Ihre E-Mail zur Verifizierung.', ]); } public function login(Request $request) { $validator = Validator::make($request->all(), [ 'identifier' => 'required|string', 'password' => 'required|string', 'remember' => 'boolean', 'locale' => 'nullable|string', ]); if ($validator->fails()) { return response()->json(['errors' => $validator->errors()], 422); } $packageId = $request->session()->get('selected_package_id'); // Custom Auth für Identifier (E-Mail oder Username) $identifier = $request->identifier; $user = User::where('email', $identifier) ->orWhere('username', $identifier) ->first(); if (!$user || !Hash::check($request->password, $user->password)) { return response()->json([ 'errors' => ['identifier' => ['Ungültige Anmeldedaten.']] ], 422); } Auth::login($user, $request->boolean('remember')); $request->session()->regenerate(); // Checkout-spezifische Logik DB::transaction(function () use ($request, $user, $packageId) { if ($packageId && !$user->pending_purchase) { $user->update(['pending_purchase' => true]); $request->session()->put('pending_package_id', $packageId); } }); return response()->json([ 'user' => [ 'id' => $user->id, 'email' => $user->email, 'name' => $user->name ?? null, 'pending_purchase' => $user->pending_purchase ?? false, ], 'message' => 'Login erfolgreich', ]); } public function trackAbandonedCheckout(Request $request) { $validated = $request->validate([ 'package_id' => 'required|exists:packages,id', 'email' => 'nullable|email', 'step' => 'nullable|string|in:package,auth,payment,confirmation', 'checkout_state' => 'nullable|array', ]); $user = Auth::user(); if (! $user && ! empty($validated['email'])) { $user = User::where('email', $validated['email'])->first(); } if (! $user) { return response()->json(['status' => 'skipped'], 202); } $package = Package::find($validated['package_id']); if (! $package) { return response()->json(['status' => 'missing_package'], 404); } $stepMap = [ 'package' => 1, 'auth' => 2, 'payment' => 3, 'confirmation' => 4, ]; $lastStep = $stepMap[$validated['step'] ?? 'package'] ?? 1; $checkout = AbandonedCheckout::firstOrNew([ 'user_id' => $user->id, 'package_id' => $package->id, ]); $checkout->email = $user->email; $checkout->checkout_state = $validated['checkout_state'] ?? [ 'step' => $validated['step'] ?? 'package', ]; $checkout->last_step = $lastStep; $checkout->abandoned_at = now(); if (! $checkout->exists || $checkout->converted) { $checkout->reminder_stage = 'none'; $checkout->reminded_at = null; } if (! $checkout->expires_at || $checkout->expires_at->isPast()) { $checkout->expires_at = now()->addDays(30); } $checkout->converted = false; $checkout->save(); return response()->json(['status' => 'tracked']); } public function createPaymentIntent(Request $request) { $request->validate([ 'package_id' => 'required|exists:packages,id', ]); $package = Package::findOrFail($request->package_id); \Log::info('Create Payment Intent', [ 'package_id' => $package->id, 'package_name' => $package->name, 'price' => $package->price, 'is_free' => $package->is_free, 'user_id' => Auth::id(), ]); if ($package->is_free) { \Log::info('Free package detected, returning null client_secret'); return response()->json([ 'client_secret' => null, 'free_package' => true, ]); } // Stripe API Key setzen Stripe::setApiKey(config('services.stripe.secret')); try { $paymentIntent = PaymentIntent::create([ 'amount' => $package->price * 100, // Stripe erwartet Cent 'currency' => 'eur', 'metadata' => [ 'package_id' => $package->id, 'user_id' => Auth::id(), ], ]); \Log::info('PaymentIntent created successfully', [ 'payment_intent_id' => $paymentIntent->id, 'client_secret' => substr($paymentIntent->client_secret, 0, 50) . '...', ]); return response()->json([ 'client_secret' => $paymentIntent->client_secret, ]); } catch (\Exception $e) { \Log::error('Stripe PaymentIntent creation failed', [ 'error' => $e->getMessage(), 'package_id' => $package->id, ]); return response()->json([ 'error' => 'Fehler beim Erstellen der Zahlungsdaten: ' . $e->getMessage(), ], 500); } } public function confirmPayment(Request $request) { $request->validate([ 'payment_intent_id' => 'required|string', 'package_id' => 'required|exists:packages,id', ]); // Stripe API Key setzen Stripe::setApiKey(config('services.stripe.secret')); $paymentIntent = PaymentIntent::retrieve($request->payment_intent_id); if ($paymentIntent->status !== 'succeeded') { return response()->json([ 'error' => 'Zahlung nicht erfolgreich.', ], 400); } $package = Package::findOrFail($request->package_id); $user = Auth::user(); // Package dem Tenant zuweisen $user->tenant->packages()->attach($package->id, [ 'purchased_at' => now(), 'expires_at' => now()->addYear(), 'is_active' => true, ]); // pending_purchase zurücksetzen $user->update(['pending_purchase' => false]); return response()->json([ 'message' => 'Zahlung erfolgreich bestätigt.', ]); } public function handlePayPalReturn(Request $request) { $orderId = $request->query('orderID'); if (!$orderId) { return redirect('/checkout')->with('error', 'Ungültige PayPal-Rückkehr.'); } $user = Auth::user(); if (!$user) { return redirect('/login')->with('error', 'Bitte melden Sie sich an.'); } try { // Capture aufrufen $paypalController = new PayPalController(); $captureRequest = new Request(['order_id' => $orderId]); $captureResponse = $paypalController->captureOrder($captureRequest); if ($captureResponse->getStatusCode() !== 200 || !isset($captureResponse->getData(true)['status']) || $captureResponse->getData(true)['status'] !== 'captured') { Log::error('PayPal capture failed in return handler', ['order_id' => $orderId, 'response' => $captureResponse->getData(true)]); return redirect('/checkout')->with('error', 'Zahlung konnte nicht abgeschlossen werden.'); } // PackagePurchase finden (erzeugt durch captureOrder) $purchase = \App\Models\PackagePurchase::where('provider_id', $orderId) ->where('tenant_id', $user->tenant_id) ->latest() ->first(); if (!$purchase) { Log::error('No PackagePurchase found after PayPal capture', ['order_id' => $orderId, 'tenant_id' => $user->tenant_id]); return redirect('/checkout')->with('error', 'Kauf konnte nicht verifiziert werden.'); } $package = \App\Models\Package::find($purchase->package_id); if (!$package) { return redirect('/checkout')->with('error', 'Paket nicht gefunden.'); } // TenantPackage zuweisen (ähnlich Stripe) $user->tenant->packages()->attach($package->id, [ 'purchased_at' => now(), 'expires_at' => now()->addYear(), 'is_active' => true, ]); // pending_purchase zurücksetzen $user->update(['pending_purchase' => false]); Log::info('PayPal payment completed and package assigned', ['order_id' => $orderId, 'package_id' => $package->id, 'tenant_id' => $user->tenant_id]); return redirect('/success/' . $package->id)->with('success', 'Zahlung erfolgreich! Ihr Paket wurde aktiviert.'); } catch (\Exception $e) { Log::error('Error in PayPal return handler', ['order_id' => $orderId, 'error' => $e->getMessage()]); return redirect('/checkout')->with('error', 'Fehler beim Abschließen der Zahlung: ' . $e->getMessage()); } } }