155 lines
7.4 KiB
PHP
155 lines
7.4 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
require __DIR__ . '/dev-db.php';
|
|
require_once __DIR__ . '/../app/saas-auth.php';
|
|
require_once __DIR__ . '/../app/legal-requests.php';
|
|
require_once __DIR__ . '/../app/data-export.php';
|
|
|
|
$pdo = dev_pdo();
|
|
$suffix = bin2hex(random_bytes(4));
|
|
$slug = 'legal-check-' . $suffix;
|
|
$email = $slug . '@test.local';
|
|
$failures = [];
|
|
$passes = 0;
|
|
$assert = static function (string $label, bool $condition) use (&$failures, &$passes): void {
|
|
if ($condition) {
|
|
$passes++;
|
|
echo "PASS {$label}\n";
|
|
} else {
|
|
$failures[] = $label;
|
|
echo "FAIL {$label}\n";
|
|
}
|
|
};
|
|
|
|
$missingAcceptance = saas_register_tenant_owner($pdo, [
|
|
'tenant_name' => 'Legal Check Invalid',
|
|
'tenant_slug' => $slug . '-invalid',
|
|
'display_name' => 'Legal Check',
|
|
'email' => 'invalid-' . $email,
|
|
'password' => 'Legal-check-123!',
|
|
'password_confirm' => 'Legal-check-123!',
|
|
'customer_type' => 'consumer',
|
|
]);
|
|
$assert('Registrierung ohne Rechtstextannahme wird abgelehnt', $missingAcceptance['ok'] === false);
|
|
|
|
$registration = saas_register_tenant_owner($pdo, [
|
|
'tenant_name' => 'Legal Compliance Check',
|
|
'tenant_slug' => $slug,
|
|
'display_name' => 'Legal Check',
|
|
'email' => $email,
|
|
'password' => 'Legal-check-123!',
|
|
'password_confirm' => 'Legal-check-123!',
|
|
'customer_type' => 'consumer',
|
|
'accept_terms' => true,
|
|
'acknowledge_privacy' => true,
|
|
'accept_dpa' => true,
|
|
]);
|
|
$assert('B2C-Registrierung gelingt mit Pflichtbestätigungen', $registration['ok'] === true);
|
|
|
|
$tenantId = (int)($registration['identity']['tenant_id'] ?? 0);
|
|
$userId = (int)($registration['identity']['user_id'] ?? 0);
|
|
if ($tenantId > 0) {
|
|
$stmt = $pdo->prepare('SELECT customer_type FROM tenants WHERE id = ?');
|
|
$stmt->execute([$tenantId]);
|
|
$assert('Vertragstyp Verbraucher wird gespeichert', $stmt->fetchColumn() === 'consumer');
|
|
|
|
$stmt = $pdo->prepare('SELECT document_type, document_version, metadata_json FROM legal_acceptances WHERE tenant_id = ? ORDER BY document_type');
|
|
$stmt->execute([$tenantId]);
|
|
$acceptances = $stmt->fetchAll();
|
|
$types = array_column($acceptances, 'document_type');
|
|
$assert('AGB, AVV und Datenschutzhinweis werden versioniert protokolliert', $types === ['dpa', 'privacy_notice', 'terms']);
|
|
$acceptanceEvidence = json_decode((string)$acceptances[0]['metadata_json'], true);
|
|
$assert('Rechtstext-Hash ist im Nachweis enthalten', !empty($acceptanceEvidence['document_sha256']));
|
|
$assert('Vertragsreferenz bleibt im Nachweis auch nach Kontolöschung erhalten', ($acceptanceEvidence['tenant_slug'] ?? null) === $slug && ($acceptanceEvidence['user_email'] ?? null) === $email);
|
|
|
|
$input = [
|
|
'request_type' => 'cancellation',
|
|
'requester_name' => 'Legal Check',
|
|
'requester_email' => $email,
|
|
'contract_reference' => $slug,
|
|
'cancellation_kind' => 'ordinary',
|
|
'requested_end' => 'earliest',
|
|
'request_reason' => '',
|
|
'metadata' => ['cancellation_kind' => 'ordinary'],
|
|
];
|
|
$stored = app_store_legal_request($pdo, $input);
|
|
$processing = app_process_cancellation_request($pdo, $stored, $input);
|
|
$assert('Kündigung wird eindeutig dem Vertrag zugeordnet', $stored['tenant_id'] === $tenantId);
|
|
$assert('Kostenloser Vertrag wird zum bestätigten Zeitpunkt beendet', $processing['status'] === 'contract_ended');
|
|
$confirmation = app_fetch_legal_request_by_token($pdo, $stored['access_token']);
|
|
$assert('Dauerhafte Kündigungsbestätigung ist per Geheimtoken abrufbar', $confirmation !== null && $confirmation['reference_code'] === $stored['reference_code']);
|
|
$_GET = ['token' => $stored['access_token']];
|
|
ob_start();
|
|
include __DIR__ . '/../rechtserklaerung-bestaetigung.php';
|
|
$confirmationText = (string)ob_get_clean();
|
|
$_GET = [];
|
|
$assert('Bestätigungsdownload lässt sich mit einem gültigen Token rendern', str_contains($confirmationText, $stored['reference_code']));
|
|
|
|
$export = app_export_tenant_data($pdo, $tenantId);
|
|
$assert('Datenexport enthält Legal-Nachweise', count($export['legal_acceptances']) === 3 && count($export['legal_requests']) === 1);
|
|
|
|
$pdo->prepare('DELETE FROM legal_requests WHERE reference_code = ?')->execute([$stored['reference_code']]);
|
|
$pdo->prepare('DELETE FROM legal_acceptances WHERE tenant_id = ?')->execute([$tenantId]);
|
|
$pdo->prepare('DELETE FROM tenants WHERE id = ?')->execute([$tenantId]);
|
|
$pdo->prepare('DELETE FROM users WHERE id = ?')->execute([$userId]);
|
|
}
|
|
|
|
$withdrawalSlug = $slug . '-withdrawal';
|
|
$withdrawalEmail = 'withdrawal-' . $email;
|
|
$withdrawalRegistration = saas_register_tenant_owner($pdo, [
|
|
'tenant_name' => 'Legal Withdrawal Check',
|
|
'tenant_slug' => $withdrawalSlug,
|
|
'display_name' => 'Withdrawal Check',
|
|
'email' => $withdrawalEmail,
|
|
'password' => 'Legal-check-123!',
|
|
'password_confirm' => 'Legal-check-123!',
|
|
'customer_type' => 'consumer',
|
|
'accept_terms' => true,
|
|
'acknowledge_privacy' => true,
|
|
'accept_dpa' => true,
|
|
]);
|
|
if ($withdrawalRegistration['ok']) {
|
|
$withdrawalTenantId = (int)$withdrawalRegistration['identity']['tenant_id'];
|
|
$withdrawalUserId = (int)$withdrawalRegistration['identity']['user_id'];
|
|
$withdrawalInput = [
|
|
'request_type' => 'withdrawal',
|
|
'requester_name' => 'Withdrawal Check',
|
|
'requester_email' => $withdrawalEmail,
|
|
'contract_reference' => $withdrawalSlug,
|
|
'request_reason' => '',
|
|
];
|
|
$withdrawalStored = app_store_legal_request($pdo, $withdrawalInput);
|
|
$withdrawalProcessing = app_process_withdrawal_request($pdo, $withdrawalStored);
|
|
$assert('B2C-Widerruf innerhalb von 14 Tagen beendet den kostenlosen Vertrag', $withdrawalProcessing['status'] === 'withdrawal_effective');
|
|
$stmt = $pdo->prepare('SELECT contract_ends_at FROM tenants WHERE id = ?');
|
|
$stmt->execute([$withdrawalTenantId]);
|
|
$assert('Widerruf sperrt den Vertrag technisch', $stmt->fetchColumn() !== null);
|
|
|
|
$pdo->prepare('DELETE FROM legal_requests WHERE reference_code = ?')->execute([$withdrawalStored['reference_code']]);
|
|
$pdo->prepare('DELETE FROM legal_acceptances WHERE tenant_id = ?')->execute([$withdrawalTenantId]);
|
|
$pdo->prepare('DELETE FROM tenants WHERE id = ?')->execute([$withdrawalTenantId]);
|
|
$pdo->prepare('DELETE FROM users WHERE id = ?')->execute([$withdrawalUserId]);
|
|
} else {
|
|
$assert('B2C-Widerrufstest konnte registriert werden', false);
|
|
}
|
|
|
|
$css = file_get_contents(__DIR__ . '/../assets/css/main.css') ?: '';
|
|
$assert('Kein dynamischer Google-Fonts-Abruf im Haupt-CSS', !str_contains($css, 'fonts.googleapis.com'));
|
|
$assert('Widerrufsfunktion ist hervorgehoben verlinkt', str_contains(app_public_legal_footer(), 'Vertrag widerrufen'));
|
|
$assert('Kündigungsschaltfläche ist ständig verlinkt', str_contains(app_public_legal_footer(), 'Verträge hier kündigen'));
|
|
$assert('Bestellschaltfläche weist eindeutig auf die Zahlungspflicht hin', str_contains((string)file_get_contents(__DIR__ . '/../abo-bestellen.php'), 'zahlungspflichtig bestellen'));
|
|
$stripeCode = (string)file_get_contents(__DIR__ . '/../app/stripe.php');
|
|
$assert('Stripe-Portal ist auf das Ändern des Zahlungsmittels beschränkt', str_contains($stripeCode, "'type' => 'payment_method_update'"));
|
|
|
|
if ($failures !== []) {
|
|
echo "\nLegal compliance flow failed with " . count($failures) . " failure(s):\n";
|
|
foreach ($failures as $failure) {
|
|
echo "- {$failure}\n";
|
|
}
|
|
exit(1);
|
|
}
|
|
|
|
echo "\nLegal compliance flow passed with {$passes} assertions.\n";
|