198 lines
7.1 KiB
JavaScript
198 lines
7.1 KiB
JavaScript
// 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 || '',
|
||
})
|
||
|
||
/** Admin-Session (Ticketsystem-Mitarbeiter im Portal), F11. */
|
||
export const adminCookie = () =>
|
||
sessionCookie({ role: 'admin', appwriteUserId: 'u_admin', name: 'Kenso', email: 'kenso@webklar.com' })
|
||
|
||
/** Admin im Modus "Als Kunde ansehen" (portalAdmin.js /view-as): Bestellen und Aendern sind gesperrt. */
|
||
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,
|
||
}
|
||
}
|