widerrufsbelehrung hinzugefügt und in den checkout mit eingebunden. refund ins backend eingebaut.
This commit is contained in:
@@ -38,18 +38,10 @@ class LegalController extends BaseController
|
||||
public function show(Request $request, string $slug)
|
||||
{
|
||||
$locale = $request->query('lang', 'de');
|
||||
|
||||
// Support common English aliases as fallbacks
|
||||
$s = strtolower($slug);
|
||||
$aliasMap = [
|
||||
'imprint' => 'impressum',
|
||||
'privacy' => 'datenschutz',
|
||||
'terms' => 'agb',
|
||||
];
|
||||
$resolved = $aliasMap[$s] ?? $s;
|
||||
$slugs = $this->resolveSlugs($slug);
|
||||
|
||||
$page = LegalPage::query()
|
||||
->where('slug', $resolved)
|
||||
->whereIn('slug', $slugs)
|
||||
->where('is_published', true)
|
||||
->orderByDesc('version')
|
||||
->first();
|
||||
@@ -59,7 +51,7 @@ class LegalController extends BaseController
|
||||
'Legal Page Not Found',
|
||||
'The requested legal document does not exist.',
|
||||
Response::HTTP_NOT_FOUND,
|
||||
['slug' => $resolved]
|
||||
['slug' => $slugs[0]]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -77,6 +69,28 @@ class LegalController extends BaseController
|
||||
])->header('Cache-Control', 'no-store');
|
||||
}
|
||||
|
||||
protected function resolveSlugs(string $slug): array
|
||||
{
|
||||
$s = strtolower($slug);
|
||||
$aliasMap = [
|
||||
'imprint' => 'impressum',
|
||||
'privacy' => 'datenschutz',
|
||||
'terms' => 'agb',
|
||||
'withdrawal' => 'widerrufsbelehrung',
|
||||
'cancellation' => 'widerrufsbelehrung',
|
||||
'cancellation-policy' => 'widerrufsbelehrung',
|
||||
'widerruf' => 'widerrufsbelehrung',
|
||||
];
|
||||
|
||||
$canonical = $aliasMap[$s] ?? $s;
|
||||
|
||||
return array_values(array_unique(
|
||||
$canonical === 'widerrufsbelehrung'
|
||||
? ['widerrufsbelehrung', 'widerruf']
|
||||
: [$canonical]
|
||||
));
|
||||
}
|
||||
|
||||
protected function convertMarkdownToHtml(string $markdown): string
|
||||
{
|
||||
return trim((string) $this->markdown->convert($markdown));
|
||||
|
||||
@@ -20,12 +20,12 @@ class LegalPageController extends Controller
|
||||
{
|
||||
public function show(Request $request, string $locale, ?string $slug = null): Response
|
||||
{
|
||||
$resolvedSlug = $this->resolveSlug($slug);
|
||||
$slugCandidates = $this->resolveSlugs($slug);
|
||||
$page = null;
|
||||
|
||||
try {
|
||||
$page = LegalPage::query()
|
||||
->where('slug', $resolvedSlug)
|
||||
->whereIn('slug', $slugCandidates)
|
||||
->where('is_published', true)
|
||||
->orderByDesc('version')
|
||||
->first();
|
||||
@@ -37,7 +37,7 @@ class LegalPageController extends Controller
|
||||
$locale = $request->route('locale', app()->getLocale());
|
||||
|
||||
if (! $page) {
|
||||
$fallback = $this->loadFallbackDocument($resolvedSlug, $locale);
|
||||
$fallback = $this->loadFallbackDocument($slugCandidates, $locale);
|
||||
|
||||
if (! $fallback) {
|
||||
abort(404);
|
||||
@@ -50,7 +50,7 @@ class LegalPageController extends Controller
|
||||
'effectiveFrom' => null,
|
||||
'effectiveFromLabel' => null,
|
||||
'versionLabel' => null,
|
||||
'slug' => $resolvedSlug,
|
||||
'slug' => $slugCandidates[0],
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -58,7 +58,8 @@ class LegalPageController extends Controller
|
||||
?? $page->title[$page->locale_fallback]
|
||||
?? $page->title['de']
|
||||
?? $page->title['en']
|
||||
?? Str::title($resolvedSlug);
|
||||
?? Str::title($slugCandidates[0]);
|
||||
$title = Str::ucfirst($title);
|
||||
|
||||
$bodyMarkdown = $page->body_markdown[$locale]
|
||||
?? $page->body_markdown[$page->locale_fallback]
|
||||
@@ -76,11 +77,11 @@ class LegalPageController extends Controller
|
||||
? __('legal.effective_from', ['date' => $effectiveFrom->translatedFormat('d. F Y')])
|
||||
: null,
|
||||
'versionLabel' => __('legal.version', ['version' => $page->version]),
|
||||
'slug' => $resolvedSlug,
|
||||
'slug' => $slugCandidates[0],
|
||||
]);
|
||||
}
|
||||
|
||||
private function resolveSlug(?string $slug): string
|
||||
private function resolveSlugs(?string $slug): array
|
||||
{
|
||||
$slug = strtolower($slug ?? '');
|
||||
|
||||
@@ -88,9 +89,20 @@ class LegalPageController extends Controller
|
||||
'imprint' => 'impressum',
|
||||
'privacy' => 'datenschutz',
|
||||
'terms' => 'agb',
|
||||
'withdrawal' => 'widerrufsbelehrung',
|
||||
'cancellation' => 'widerrufsbelehrung',
|
||||
'cancellation-policy' => 'widerrufsbelehrung',
|
||||
'widerruf' => 'widerrufsbelehrung',
|
||||
];
|
||||
|
||||
return $aliases[$slug] ?? $slug ?: 'impressum';
|
||||
$canonical = $aliases[$slug] ?? $slug ?: 'impressum';
|
||||
|
||||
// Support both slugs for withdrawal in case DB uses a shorter slug
|
||||
$fallbacks = $canonical === 'widerrufsbelehrung'
|
||||
? ['widerrufsbelehrung', 'widerruf']
|
||||
: [$canonical];
|
||||
|
||||
return array_values(array_unique($fallbacks));
|
||||
}
|
||||
|
||||
private function convertMarkdownToHtml(string $markdown): string
|
||||
@@ -111,7 +123,7 @@ class LegalPageController extends Controller
|
||||
return trim((string) $converter->convert($markdown));
|
||||
}
|
||||
|
||||
private function loadFallbackDocument(string $slug, string $locale): ?array
|
||||
private function loadFallbackDocument(array $slugCandidates, string $locale): ?array
|
||||
{
|
||||
$candidates = array_unique([
|
||||
strtolower($locale),
|
||||
@@ -120,20 +132,22 @@ class LegalPageController extends Controller
|
||||
'en',
|
||||
]);
|
||||
|
||||
foreach ($candidates as $candidateLocale) {
|
||||
$path = base_path("docs/legal/{$slug}-{$candidateLocale}.md");
|
||||
foreach ($slugCandidates as $slug) {
|
||||
foreach ($candidates as $candidateLocale) {
|
||||
$path = base_path("docs/legal/{$slug}-{$candidateLocale}.md");
|
||||
|
||||
if (! is_file($path)) {
|
||||
continue;
|
||||
if (! is_file($path)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$markdown = (string) file_get_contents($path);
|
||||
$title = $this->extractTitleFromMarkdown($markdown) ?? Str::title($slug);
|
||||
|
||||
return [
|
||||
'markdown' => $markdown,
|
||||
'title' => $title,
|
||||
];
|
||||
}
|
||||
|
||||
$markdown = (string) file_get_contents($path);
|
||||
$title = $this->extractTitleFromMarkdown($markdown) ?? Str::title($slug);
|
||||
|
||||
return [
|
||||
'markdown' => $markdown,
|
||||
'title' => $title,
|
||||
];
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -132,6 +132,13 @@ class MarketingController extends Controller
|
||||
Log::info('Buy packages called', ['auth' => Auth::check(), 'locale' => $locale, 'package_id' => $packageId]);
|
||||
$package = Package::findOrFail($packageId);
|
||||
|
||||
$requiresWaiver = (bool) ($package->activates_immediately ?? true);
|
||||
|
||||
$request->validate([
|
||||
'accepted_terms' => ['sometimes', 'boolean', 'accepted'],
|
||||
'accepted_waiver' => ['sometimes', 'boolean'],
|
||||
]);
|
||||
|
||||
$couponCode = $this->rememberCouponFromRequest($request, $package);
|
||||
|
||||
if (! Auth::check()) {
|
||||
@@ -194,6 +201,16 @@ class MarketingController extends Controller
|
||||
|
||||
$this->checkoutSessions->selectProvider($session, CheckoutSession::PROVIDER_PADDLE);
|
||||
|
||||
$now = now();
|
||||
|
||||
$session->forceFill([
|
||||
'accepted_terms_at' => $request->boolean('accepted_terms') ? $now : null,
|
||||
'accepted_privacy_at' => $request->boolean('accepted_terms') ? $now : null,
|
||||
'accepted_withdrawal_notice_at' => $request->boolean('accepted_terms') ? $now : null,
|
||||
'digital_content_waiver_at' => $requiresWaiver && $request->boolean('accepted_waiver') ? $now : null,
|
||||
'legal_version' => $this->resolveLegalVersion(),
|
||||
])->save();
|
||||
|
||||
$appliedDiscountId = null;
|
||||
|
||||
if ($couponCode) {
|
||||
@@ -219,6 +236,9 @@ class MarketingController extends Controller
|
||||
'metadata' => [
|
||||
'checkout_session_id' => $session->id,
|
||||
'coupon_code' => $couponCode,
|
||||
'legal_version' => $session->legal_version,
|
||||
'accepted_terms' => (bool) $session->accepted_terms_at,
|
||||
'accepted_waiver' => $requiresWaiver && (bool) $session->digital_content_waiver_at,
|
||||
],
|
||||
'discount_id' => $appliedDiscountId,
|
||||
]);
|
||||
@@ -628,4 +648,9 @@ class MarketingController extends Controller
|
||||
'excerpt_html' => $this->convertMarkdownToHtml($excerpt),
|
||||
];
|
||||
}
|
||||
|
||||
protected function resolveLegalVersion(): string
|
||||
{
|
||||
return config('app.legal_version', now()->toDateString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,8 @@ class PaddleCheckoutController extends Controller
|
||||
'return_url' => ['nullable', 'url'],
|
||||
'inline' => ['sometimes', 'boolean'],
|
||||
'coupon_code' => ['nullable', 'string', 'max:64'],
|
||||
'accepted_terms' => ['required', 'boolean', 'accepted'],
|
||||
'accepted_waiver' => ['sometimes', 'boolean'],
|
||||
]);
|
||||
|
||||
$user = Auth::user();
|
||||
@@ -44,12 +46,30 @@ class PaddleCheckoutController extends Controller
|
||||
throw ValidationException::withMessages(['package_id' => 'Package is not linked to a Paddle price.']);
|
||||
}
|
||||
|
||||
$requiresWaiver = (bool) ($package->activates_immediately ?? true);
|
||||
|
||||
if ($requiresWaiver && ! $request->boolean('accepted_waiver')) {
|
||||
throw ValidationException::withMessages([
|
||||
'accepted_waiver' => 'Ein sofortiger Beginn der digitalen Dienstleistung erfordert Ihre ausdrückliche Zustimmung.',
|
||||
]);
|
||||
}
|
||||
|
||||
$session = $this->sessions->createOrResume($user, $package, [
|
||||
'tenant' => $tenant,
|
||||
]);
|
||||
|
||||
$this->sessions->selectProvider($session, CheckoutSession::PROVIDER_PADDLE);
|
||||
|
||||
$now = now();
|
||||
|
||||
$session->forceFill([
|
||||
'accepted_terms_at' => $now,
|
||||
'accepted_privacy_at' => $now,
|
||||
'accepted_withdrawal_notice_at' => $now,
|
||||
'digital_content_waiver_at' => $requiresWaiver ? $now : null,
|
||||
'legal_version' => $this->resolveLegalVersion(),
|
||||
])->save();
|
||||
|
||||
$couponCode = Str::upper(trim((string) ($data['coupon_code'] ?? '')));
|
||||
$discountId = null;
|
||||
|
||||
@@ -80,6 +100,9 @@ class PaddleCheckoutController extends Controller
|
||||
'tenant_id' => (string) $tenant->id,
|
||||
'package_id' => (string) $package->id,
|
||||
'checkout_session_id' => (string) $session->id,
|
||||
'legal_version' => $session->legal_version,
|
||||
'accepted_terms' => '1',
|
||||
'accepted_waiver' => $requiresWaiver && $request->boolean('accepted_waiver') ? '1' : '0',
|
||||
],
|
||||
'customer' => array_filter([
|
||||
'email' => $user->email,
|
||||
@@ -94,6 +117,9 @@ class PaddleCheckoutController extends Controller
|
||||
'metadata' => [
|
||||
'checkout_session_id' => $session->id,
|
||||
'coupon_code' => $couponCode ?: null,
|
||||
'legal_version' => $session->legal_version,
|
||||
'accepted_terms' => true,
|
||||
'accepted_waiver' => $requiresWaiver && $request->boolean('accepted_waiver'),
|
||||
],
|
||||
'discount_id' => $discountId,
|
||||
]);
|
||||
@@ -109,4 +135,9 @@ class PaddleCheckoutController extends Controller
|
||||
|
||||
return response()->json($checkout);
|
||||
}
|
||||
|
||||
protected function resolveLegalVersion(): string
|
||||
{
|
||||
return config('app.legal_version', now()->toDateString());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user