verschieben des sofortigen verzichts auf das Widerrrufsrecht zum Anlegen des Events

This commit is contained in:
Codex Agent
2025-12-22 13:11:16 +01:00
parent 84234bfb8e
commit c947e638eb
29 changed files with 877 additions and 374 deletions

View File

@@ -8,10 +8,12 @@ use App\Http\Requests\Tenant\EventStoreRequest;
use App\Http\Resources\Tenant\EventJoinTokenResource;
use App\Http\Resources\Tenant\EventResource;
use App\Http\Resources\Tenant\PhotoResource;
use App\Models\CheckoutSession;
use App\Models\Event;
use App\Models\EventPackage;
use App\Models\GuestNotification;
use App\Models\Package;
use App\Models\PackagePurchase;
use App\Models\Photo;
use App\Models\Tenant;
use App\Services\EventJoinTokenService;
@@ -116,6 +118,17 @@ class EventController extends Controller
]);
}
$requiresWaiver = $package->isEndcustomer();
$latestPurchase = $requiresWaiver ? $this->resolveLatestPackagePurchase($tenant, $package) : null;
$existingWaiver = $latestPurchase ? data_get($latestPurchase->metadata, 'consents.digital_content_waiver_at') : null;
$needsWaiver = $requiresWaiver && ! $existingWaiver;
if ($needsWaiver && ! $request->boolean('accepted_waiver')) {
throw ValidationException::withMessages([
'accepted_waiver' => 'Ein sofortiger Beginn der digitalen Dienstleistung erfordert Ihre ausdrückliche Zustimmung.',
]);
}
$eventData = array_merge($validated, [
'tenant_id' => $tenantId,
'status' => $validated['status'] ?? 'draft',
@@ -180,15 +193,21 @@ class EventController extends Controller
'gallery_expires_at' => $package->gallery_days ? now()->addDays($package->gallery_days) : null,
]);
$note = sprintf('Event #%d created (%s)', $event->id, $event->name);
if ($package->isReseller()) {
$note = sprintf('Event #%d created (%s)', $event->id, $event->name);
if (! $tenant->consumeEventAllowance(1, 'event.create', $note)) {
throw new HttpException(402, 'Insufficient package allowance.');
if (! $tenant->consumeEventAllowance(1, 'event.create', $note)) {
throw new HttpException(402, 'Insufficient package allowance.');
}
}
return $event;
});
if ($needsWaiver) {
$this->recordEventStartWaiver($tenant, $package, $latestPurchase);
}
$tenant->refresh();
$event->load(['eventType', 'tenant', 'eventPackages.package', 'eventPackages.addons']);
@@ -200,6 +219,45 @@ class EventController extends Controller
], 201);
}
private function resolveLatestPackagePurchase(Tenant $tenant, Package $package): ?PackagePurchase
{
return PackagePurchase::query()
->where('tenant_id', $tenant->id)
->where('package_id', $package->id)
->orderByDesc('purchased_at')
->orderByDesc('id')
->first();
}
private function recordEventStartWaiver(Tenant $tenant, Package $package, ?PackagePurchase $purchase): void
{
$timestamp = now();
$legalVersion = config('app.legal_version', $timestamp->toDateString());
if ($purchase) {
$metadata = $purchase->metadata ?? [];
$consents = is_array($metadata['consents'] ?? null) ? $metadata['consents'] : [];
$consents['digital_content_waiver_at'] = $timestamp->toIso8601String();
$consents['legal_version'] = $consents['legal_version'] ?? $legalVersion;
$metadata['consents'] = $consents;
$purchase->metadata = $metadata;
$purchase->save();
}
$session = CheckoutSession::query()
->where('tenant_id', $tenant->id)
->where('package_id', $package->id)
->where('status', CheckoutSession::STATUS_COMPLETED)
->orderByDesc('completed_at')
->first();
if ($session && ! $session->digital_content_waiver_at) {
$session->digital_content_waiver_at = $timestamp;
$session->legal_version = $session->legal_version ?? $legalVersion;
$session->save();
}
}
public function show(Request $request, Event $event): JsonResponse
{
$tenantId = $request->attributes->get('tenant_id');

View File

@@ -4,6 +4,8 @@ namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\EventPackageAddon;
use App\Services\Paddle\PaddleCustomerPortalService;
use App\Services\Paddle\PaddleCustomerService;
use App\Services\Paddle\PaddleTransactionService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
@@ -12,7 +14,11 @@ use Illuminate\Support\Facades\Log;
class TenantBillingController extends Controller
{
public function __construct(private readonly PaddleTransactionService $paddleTransactions) {}
public function __construct(
private readonly PaddleTransactionService $paddleTransactions,
private readonly PaddleCustomerService $paddleCustomers,
private readonly PaddleCustomerPortalService $portalSessions,
) {}
public function transactions(Request $request): JsonResponse
{
@@ -116,4 +122,44 @@ class TenantBillingController extends Controller
],
]);
}
public function portal(Request $request): JsonResponse
{
$tenant = $request->attributes->get('tenant');
if (! $tenant) {
return response()->json([
'message' => 'Tenant not found.',
], 404);
}
try {
$customerId = $this->paddleCustomers->ensureCustomerId($tenant);
$session = $this->portalSessions->createSession($customerId);
} catch (\Throwable $exception) {
Log::warning('Failed to create Paddle customer portal session', [
'tenant_id' => $tenant->id,
'error' => $exception->getMessage(),
]);
return response()->json([
'message' => 'Failed to create Paddle customer portal session.',
], 502);
}
$url = Arr::get($session, 'data.urls.general.overview')
?? Arr::get($session, 'data.urls.general')
?? Arr::get($session, 'urls.general.overview')
?? Arr::get($session, 'urls.general');
if (! $url) {
return response()->json([
'message' => 'Paddle customer portal session missing URL.',
], 502);
}
return response()->json([
'url' => $url,
]);
}
}