// testApp.js zuerst: es prueft beim Laden, dass useTestEnv() vor config.js gelaufen ist import { sessionCookie } from './testApp.js' import { config } from '../../server/config.js' /** * Feste Testdaten für die Routen-Tests (Aufgaben 7–13): Kunden c1–c4, Abo-Dokumente, Zustimmung, * Session-Cookies. seedFixtures(aw) legt Kunden und Abos in den Appwrite-Nachbau; c3 hat kein Abo * (Neuabschluss-Tests), c4 ist ein Testkonto (ABO_TEST_EMAILS=test@example.invalid im Test setzen). * Erst nach useTestEnv() dynamisch importieren (siehe testApp.js). */ const DAY_MS = 86400000 // Sekundengenau wie Stripe (unix-Zeitstempel): der Spiegel schreibt toIso(unix) und trifft so die // Fixture-Werte wortgleich (z. B. storagePaidPeriodEnd = currentPeriodEnd nach einem Speicher-Plus) const daysFromNow = (days) => new Date(Math.floor((Date.now() + days * DAY_MS) / 1000) * 1000).toISOString() export const customers = { c1: { $id: 'c1', appwriteUserId: 'u1', email: 'k@example.invalid', name: 'Kunde Eins', status: 'active', portalAccessEnabled: true }, c2: { $id: 'c2', appwriteUserId: 'u2', email: 'k2@example.invalid', name: 'Kunde Zwei', status: 'active', portalAccessEnabled: true }, c3: { $id: 'c3', appwriteUserId: 'u3', email: 'k3@example.invalid', name: 'Kunde Drei', status: 'active', portalAccessEnabled: true }, c4: { $id: 'c4', appwriteUserId: 'u4', email: 'test@example.invalid', name: 'Testkonto', status: 'active', portalAccessEnabled: true }, } /** Abo-Dokument mit id als Dokument-ID und Stripe-Abo-ID (in Produktion immer gleich). */ export const subscriptionDoc = (id, overrides = {}) => ({ ...overrides, $id: id, stripeSubscriptionId: id }) // Abo seit 40 Tagen (Widerrufsfrist des Abschlusses vorbei), naechste Abbuchung in 20 Tagen const startedAt = daysFromNow(-40) /** Hosting-Abo sub_h von c1: aktiv, Fassung 4, ohne Zusatzspeicher. */ export const hostingDoc = subscriptionDoc('sub_h', { customerId: 'c1', email: 'k@example.invalid', stripeCustomerId: 'cus_c1', status: 'active', productKey: 'hosting', planKey: config.products.hosting.lookupKey, priceAmount: config.products.hosting.amountCents, startedAt, termStartAt: startedAt, currentPeriodEnd: daysFromNow(20), trialEnd: null, cancelAtPeriodEnd: false, cancelAt: null, canceledAt: null, endedAt: null, termsVersion: config.abo.termsVersion, termsAcceptedAt: startedAt, earlyStartConsentAt: startedAt, startChoice: 'sofort', consentIp: '127.0.0.1', consentUserAgent: 'test', consentTextVersion: config.abo.termsVersion, storageUnits: 0, storagePaidUnits: 0, storagePaidPeriodEnd: null, }) /** Wartungs-Abo sub_w von c1 (im Test meist per subscriptionDoc('sub_h', { ...wartungDoc }) eingespielt). */ export const wartungDoc = subscriptionDoc('sub_w', { ...hostingDoc, productKey: 'wartung', planKey: config.products.wartung.lookupKey, priceAmount: config.products.wartung.amountCents, }) /** Zweites Hosting-Abo sub_h2 von c2. */ export const hosting2Doc = subscriptionDoc('sub_h2', { ...hostingDoc, customerId: 'c2', email: 'k2@example.invalid', stripeCustomerId: 'cus_c2', }) const consentAt = new Date().toISOString() /** Zustimmung im Portal (Bestellung, Wechsel, Speicher-Plus); earlyStartConsentAt fuer den Wechsel (F16). */ export const consent = { termsVersion: config.abo.termsVersion, consentAt, consentIp: '127.0.0.1', consentUserAgent: 'test', earlyStartConsentAt: consentAt, } /** Kunden-Session; Standard c1. */ export const customerCookie = (customerId = 'c1') => sessionCookie({ customerId, appwriteUserId: customers[customerId]?.appwriteUserId || `u_${customerId}`, name: customers[customerId]?.name || '', // wie beim echten Login (auth.js) email: customers[customerId]?.email || '', }) /** Alte Mitarbeiter-Sitzung im Portal (Login bis Etappe 4): /api/auth/me beendet sie, Kunden-Routen 401. */ export const adminCookie = () => sessionCookie({ role: 'admin', appwriteUserId: 'u_admin', name: 'Kenso', email: 'kenso@webklar.com' }) /** Alte Ansicht "Als Kunde ansehen" aus dem frueheren Admin-Panel (ohne viewId): gilt als beendet (401 view_expired). */ export const viewAsCookie = (customerId = 'c1') => sessionCookie({ role: 'admin', viewAs: true, isAdmin: true, appwriteUserId: 'u_admin', adminName: 'Kenso', adminEmail: 'kenso@webklar.com', customerId, name: customers[customerId]?.name || '', email: customers[customerId]?.email || '', }) /** Kundenansicht aus dem Ticketsystem (Einmal-Link, 2 h, Kennung viewId): Mitarbeiter Andrej ohne Admin-Label. */ export const kundenansichtCookie = ({ customerId = 'c1', viewId = 'a'.repeat(32), viewExpiresAt = Date.now() + 3600000 } = {}) => sessionCookie({ role: 'admin', viewAs: true, viewId, viewExpiresAt, isAdmin: false, appwriteUserId: 'u_staff2', adminName: 'Andrej', adminEmail: 'andrej@webklar.com', customerId, name: customers[customerId]?.name || '', email: customers[customerId]?.email || '', }) /** Kunden c1–c4 und die Abos sub_h (c1) und sub_h2 (c2) in den Appwrite-Nachbau legen. */ export function seedFixtures(aw) { for (const customer of Object.values(customers)) aw.seed('customers', customer) aw.seed('subscriptions', hostingDoc) aw.seed('subscriptions', hosting2Doc) } const unix = (iso) => Math.floor(new Date(iso).getTime() / 1000) /** * Stripe-Abo in der Form der SDK-API-Version für den Stripe-Nachbau: Abo-Posten je Produkt, * dazu ein Zusatzspeicher-Posten, wenn storageUnits > 0. Die Standard-ID ist 28 Zeichen lang wie * bei Stripe (sub_ + 24); fuer den Spiegel von sub_h explizit id: 'sub_h' uebergeben. metadata * ergaenzt/ueberschreibt die Zustimmungsdaten, rest alles Weitere (status, cancel_at, ...). */ export function stripeSubscription({ id = 'sub_1SD6vPRxAbCdEfGhIjKlMnOp', customerId = 'c1', productKey = 'hosting', storageUnits = 0, metadata = {}, ...rest } = {}) { const product = config.products[productKey] const items = [ { id: `si_${id}_abo`, object: 'subscription_item', quantity: 1, price: { id: `price_${productKey}`, object: 'price', lookup_key: product.lookupKey, unit_amount: product.amountCents }, }, ] if (storageUnits > 0) { items.push({ id: `si_${id}_speicher`, object: 'subscription_item', quantity: storageUnits, price: { id: 'price_mailStorage', object: 'price', lookup_key: config.mailStorage.lookupKey, unit_amount: config.mailStorage.amountCents }, }) } return { id, object: 'subscription', status: 'active', customer: `cus_${customerId}`, start_date: unix(hostingDoc.startedAt), current_period_end: unix(hostingDoc.currentPeriodEnd), trial_end: null, cancel_at_period_end: false, cancel_at: null, canceled_at: null, ended_at: null, metadata: { webklarCustomerId: customerId, email: customers[customerId]?.email || '', productKey, termsVersion: config.abo.termsVersion, consentTextVersion: config.abo.termsVersion, termsAcceptedAt: consentAt, startChoice: 'sofort', earlyStartConsentAt: consentAt, consentIp: '127.0.0.1', consentUserAgent: 'test', ...metadata, }, items: { object: 'list', data: items }, ...rest, } }