prepare('SELECT id FROM tenants WHERE slug = ?'); $stmt->execute([$slug]); $tenantId = $stmt->fetchColumn(); if ($tenantId === false) { throw new RuntimeException("Tenant '{$slug}' was not created."); } return (int)$tenantId; } function m3_upsert_user(PDO $pdo, string $email, string $emailNorm, string $displayName): int { $stmt = $pdo->prepare( 'INSERT INTO users (email, email_norm, display_name, status) VALUES (?, ?, ?, ?) ON DUPLICATE KEY UPDATE email = VALUES(email), display_name = VALUES(display_name), status = VALUES(status)' ); $stmt->execute([$email, $emailNorm, $displayName, 'active']); $stmt = $pdo->prepare('SELECT id FROM users WHERE email_norm = ?'); $stmt->execute([$emailNorm]); $userId = $stmt->fetchColumn(); if ($userId === false) { throw new RuntimeException("User '{$emailNorm}' was not created."); } return (int)$userId; } $pdo = dev_pdo(); $applied = dev_apply_migrations($pdo); $tenantSlug = m3_env('M3_DEFAULT_TENANT_SLUG', 'default'); $tenantName = m3_env('M3_DEFAULT_TENANT_NAME', 'Kaffeeliste Bestand'); $ownerEmailNorm = m3_email_norm(getenv('M3_DEFAULT_TENANT_OWNER_EMAIL') ?: null); $stats = [ 'applied_migrations' => count($applied), 'participants' => 0, 'users' => 0, 'memberships' => 0, ]; $pdo->beginTransaction(); try { $stmt = $pdo->prepare( 'INSERT INTO tenants (slug, name, status, timezone, locale, currency_code) VALUES (?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE name = VALUES(name), status = VALUES(status), timezone = VALUES(timezone), locale = VALUES(locale), currency_code = VALUES(currency_code)' ); $stmt->execute([$tenantSlug, $tenantName, 'active', 'Europe/Berlin', 'de-DE', 'EUR']); $tenantId = m3_fetch_tenant_id($pdo, $tenantSlug); $config = $pdo->query( 'SELECT KostenproStrich, paypaluse, paypallink, strichperweb FROM kl_config ORDER BY id LIMIT 1' )->fetch() ?: [ 'KostenproStrich' => '0.20', 'paypaluse' => 0, 'paypallink' => '', 'strichperweb' => 1, ]; $stmt = $pdo->prepare( 'INSERT INTO tenant_settings (tenant_id, mark_price_cents, self_entry_enabled, paypal_enabled, paypal_url_template) VALUES (?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE mark_price_cents = VALUES(mark_price_cents), self_entry_enabled = VALUES(self_entry_enabled), paypal_enabled = VALUES(paypal_enabled), paypal_url_template = VALUES(paypal_url_template)' ); $stmt->execute([ $tenantId, m3_decimal_to_cents($config['KostenproStrich']), (int)$config['strichperweb'] === 1 ? 1 : 0, (int)$config['paypaluse'] === 1 ? 1 : 0, (string)$config['paypallink'], ]); $members = $pdo->query( 'SELECT MitarbeiterID, Name, Email, paypalname, aktiv, admin FROM kl_Mitarbeiter ORDER BY MitarbeiterID' )->fetchAll(); $upsertParticipant = $pdo->prepare( 'INSERT INTO participants (tenant_id, display_name, email, email_norm, paypal_name, active, legacy_mitarbeiter_id) VALUES (?, ?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE display_name = VALUES(display_name), email = VALUES(email), email_norm = VALUES(email_norm), paypal_name = VALUES(paypal_name), active = VALUES(active)' ); $upsertMembership = $pdo->prepare( 'INSERT INTO tenant_memberships (tenant_id, user_id, role, status, joined_at) VALUES (?, ?, ?, ?, NOW()) ON DUPLICATE KEY UPDATE role = VALUES(role), status = VALUES(status), joined_at = COALESCE(tenant_memberships.joined_at, VALUES(joined_at))' ); $linkParticipantUser = $pdo->prepare( 'UPDATE participants SET user_id = ? WHERE tenant_id = ? AND legacy_mitarbeiter_id = ?' ); foreach ($members as $member) { $email = trim((string)$member['Email']); $emailNorm = m3_email_norm($email); $displayName = trim((string)$member['Name']); if ($displayName === '') { $displayName = $emailNorm ?? ('Mitarbeiter ' . (int)$member['MitarbeiterID']); } $upsertParticipant->execute([ $tenantId, $displayName, $email !== '' ? $email : null, $emailNorm, $member['paypalname'] !== null && trim((string)$member['paypalname']) !== '' ? trim((string)$member['paypalname']) : null, (int)$member['aktiv'] === 1 ? 1 : 0, (int)$member['MitarbeiterID'], ]); $stats['participants']++; $isAdmin = (int)$member['admin'] === 1 && (int)$member['aktiv'] === 1; $isOwner = $ownerEmailNorm !== null && $emailNorm === $ownerEmailNorm && (int)$member['aktiv'] === 1; if ($emailNorm === null || (!$isAdmin && !$isOwner)) { continue; } $userId = m3_upsert_user($pdo, $email, $emailNorm, $displayName); $role = $isOwner ? 'owner' : 'admin'; $upsertMembership->execute([$tenantId, $userId, $role, 'active']); $linkParticipantUser->execute([$userId, $tenantId, (int)$member['MitarbeiterID']]); $stats['users']++; $stats['memberships']++; } $pdo->commit(); } catch (Throwable $e) { $pdo->rollBack(); fwrite(STDERR, "M3 default tenant backfill failed: {$e->getMessage()}\n"); exit(1); } echo "M3 default tenant backfill complete.\n"; echo "Tenant: {$tenantSlug}\n"; echo "Applied migrations: {$stats['applied_migrations']}\n"; echo "Participants mirrored: {$stats['participants']}\n"; echo "Users upserted: {$stats['users']}\n"; echo "Memberships upserted: {$stats['memberships']}\n";