import { test, after } from 'node:test' import assert from 'node:assert/strict' import { mkdtemp, rm } from 'node:fs/promises' import { join } from 'node:path' import { tmpdir } from 'node:os' import { startAppwriteMock } from './support/appwriteMock.js' import { startFakeStripe } from './support/fakeStripe.js' import { mailSink } from './support/mailSink.js' import { useTestEnv } from './support/testEnv.js' import { schemaKeys } from './support/schema.js' // Antrag auf Übernahmegutschrift in Fassung 6: Nachweis mit dem Satz und dem Knopf vor dem Antrag; Bedingungsversion unverändert const aw = await startAppwriteMock({ schema: { subscriptions: schemaKeys('subscriptions'), contractEvents: schemaKeys('contractEvents'), featureConsents: schemaKeys('featureConsents'), takeoverCredits: schemaKeys('takeoverCredits'), }, }) const st = await startFakeStripe() useTestEnv({ appwriteUrl: aw.url, stripeUrl: st.url }) const uploadDir = await mkdtemp(join(process.env.TMPDIR || tmpdir(), 'kn-takeover-')) Object.assign(process.env, { KUNDENANSICHT_NEU: 'pilot', KUNDENANSICHT_NEU_PILOT_EMAILS: 'K@example.invalid, k3@example.invalid', TAKEOVER_UPLOAD_DIR: uploadDir }) const { config } = await import('../server/config.js') const { startTestApp, post } = await import('./support/testApp.js') const { customerCookie, customers, kundenansichtCookie, seedFixtures } = await import('./support/fixtures.js') const { default: takeoverRoutes } = await import('../server/routes/takeoverCredits.js') const { setMailTransportForTests } = await import('../server/services/mailer.js') const { nachweisTexte, FEHLER_NACHWEIS } = await import('../server/services/bestelltexte.js') const app = await startTestApp({ '/api/abo/takeover-credits': takeoverRoutes }) setMailTransportForTests(mailSink()) after(async () => { setMailTransportForTests(null) await Promise.all([app.close(), aw.close(), st.close()]) await rm(uploadDir, { recursive: true, force: true }) // nur das eigene Verzeichnis dieses Tests }) seedFixtures(aw) config.takeover.maxOpenPerCustomer = 100 // die Grenze offener Anträge ist nicht Gegenstand dieses Tests const URL = '/api/abo/takeover-credits' const setzeKundenart = (id, wert) => aw.seed('customers', { ...customers[id], ...(wert === undefined ? {} : { kundenart: wert }) }) const antrag = (extra = {}) => ({ services: ['hosting'], provider: 'IONOS', domain: 'beispiel.invalid', invoiceAmount: '119.88', billingMonths: 12, paidUntil: new Date(Date.now() + 200 * 86400000).toISOString().slice(0, 10), message: 'Der Vertrag dort läuft noch bis Ende März.', email: 'k@example.invalid', consent: true, files: [{ name: 'rechnung.pdf', data: Buffer.from('%PDF-1.4 test').toString('base64') }], ...extra, }) const zeilen = () => [...aw.docs('featureConsents').values()].filter((d) => d.featureKey === 'gutschrift') const anzahl = () => aw.docs('takeoverCredits').size test('Fassung 6: Nachweis mit dem Satz und dem Knopf, Kundenart aus dem Dokument, Bedingungsversion unverändert', async () => { setzeKundenart('c1', 'unternehmen') const n0 = zeilen().length const res = await post(URL, antrag({ termsVersion: config.abo.termsVersionNeu, kundenart: 'privat', unternehmer: false }), { cookie: customerCookie() }) assert.equal(res.status, 201, JSON.stringify(res.body)) const [z] = zeilen().slice(n0) assert.deepEqual([z.kundenart, z.projectId, z.stripeSessionId, z.customerId], ['unternehmen', '', '', 'c1']) assert.deepEqual(JSON.parse(z.texte), nachweisTexte('gutschrift', {})) assert.deepEqual(JSON.parse(z.fassungen), { zustimmung: '2026-09-30', bezug: '', wortlaut: 'entwurf' }) assert.equal(config.takeover.conditionsVersion, '2026-09-30') assert.equal(aw.docs('takeoverCredits').get(res.body.request.id).conditionsVersion, '2026-09-30') }) test('Privat und leer: Nachweis mit privat, nie mit dem Wert aus dem Body', async () => { for (const art of ['privat', undefined, 'firma']) { setzeKundenart('c1', art) const res = await post(URL, antrag({ termsVersion: config.abo.termsVersionNeu, kundenart: 'unternehmen', unternehmer: true }), { cookie: customerCookie() }) assert.equal(res.status, 201, JSON.stringify(res.body)) assert.equal(zeilen().at(-1).kundenart, 'privat', String(art)) } }) test('Ohne Fassung 6 kein Nachweis; ungültige Eingabe und Nachweisfehler legen keinen Antrag an', async () => { setzeKundenart('c1', 'unternehmen') const n0 = zeilen().length assert.equal((await post(URL, antrag(), { cookie: customerCookie() })).status, 201) assert.equal(zeilen().length, n0) assert.equal((await post(URL, antrag({ termsVersion: config.abo.termsVersion }), { cookie: customerCookie() })).status, 201) assert.equal(zeilen().length, n0) const a1 = anzahl() assert.equal((await post(URL, antrag({ termsVersion: config.abo.termsVersionNeu, provider: '' }), { cookie: customerCookie() })).status, 400) aw.failNext({ collection: config.collections.featureConsents, method: 'POST' }) const f = await post(URL, antrag({ termsVersion: config.abo.termsVersionNeu }), { cookie: customerCookie() }) assert.deepEqual([f.status, f.body.error, anzahl(), zeilen().length], [500, FEHLER_NACHWEIS, a1, n0]) const fremd = await post(URL, antrag({ termsVersion: config.abo.termsVersionNeu }), { cookie: customerCookie('c2') }) assert.equal(fremd.status, 201) // c2 ist kein Pilot: Fassung 6 zählt nicht, der Antrag läuft auf dem alten Weg assert.equal(zeilen().length, n0) }) test('Mitarbeiter-Kundenansicht stellt keinen Antrag und schreibt keinen Nachweis', async () => { const n0 = zeilen().length const a0 = anzahl() const r = await post(URL, antrag({ termsVersion: config.abo.termsVersionNeu }), { cookie: kundenansichtCookie({ customerId: 'c1' }) }) assert.deepEqual([r.status, zeilen().length, anzahl()], [403, n0, a0]) })