Kundenansicht neu P7: K01 und K12 behaupten für Betriebe kein Sofortbeginn-Verlangen
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
4e0e42f633
commit
528ca0875e
5 files changed
+134
-8
No files matched your search
@@ -0,0 +1,120 @@
|
||||
import { test, after } from 'node:test'
|
||||
import assert from 'node:assert/strict'
|
||||
import { startAppwriteMock } from './support/appwriteMock.js'
|
||||
import { startFakeStripe } from './support/fakeStripe.js'
|
||||
import { useTestEnv } from './support/testEnv.js'
|
||||
import { schemaKeys } from './support/schema.js'
|
||||
import { mailSink } from './support/mailSink.js'
|
||||
|
||||
// K01 und K12 behaupten für Betriebe (Fassung 6 ohne Sofortbeginn-Zeitstempel) kein „ausdrücklich verlangt“
|
||||
const aw = await startAppwriteMock({
|
||||
schema: {
|
||||
subscriptions: schemaKeys('subscriptions'),
|
||||
contractEvents: schemaKeys('contractEvents'),
|
||||
hourCredits: schemaKeys('hourCredits'),
|
||||
featureConsents: schemaKeys('featureConsents'),
|
||||
},
|
||||
})
|
||||
const st = await startFakeStripe()
|
||||
useTestEnv({ appwriteUrl: aw.url, stripeUrl: st.url })
|
||||
Object.assign(process.env, { KUNDENANSICHT_NEU: 'pilot', KUNDENANSICHT_NEU_PILOT_EMAILS: 'K@example.invalid, k3@example.invalid' })
|
||||
const { config } = await import('../server/config.js')
|
||||
const { startTestApp, postWebhook } = await import('./support/testApp.js')
|
||||
const { hostingDoc, consent, seedFixtures, stripeSubscription } = await import('./support/fixtures.js')
|
||||
const { default: aboRoutes } = await import('../server/routes/abo.js')
|
||||
const { switchToWartung } = await import('../server/services/planSwitch.js')
|
||||
const { listContractEvents } = await import('../server/services/contractEvents.js')
|
||||
const { deleteDocument } = await import('../server/services/appwriteAdmin.js')
|
||||
const { setMailTransportForTests } = await import('../server/services/mailer.js')
|
||||
const { loadTemplate, renderMail } = await import('../server/services/mailTemplates.js')
|
||||
|
||||
const app = await startTestApp({ '/api/abo': aboRoutes })
|
||||
const mails = mailSink()
|
||||
setMailTransportForTests(mails)
|
||||
after(() => {
|
||||
setMailTransportForTests(null)
|
||||
return Promise.all([app.close(), aw.close(), st.close()])
|
||||
})
|
||||
seedFixtures(aw)
|
||||
|
||||
const price = (id, lookup_key, unit_amount) => ({ id, object: 'price', active: true, lookup_key, unit_amount, recurring: { interval: 'month' } })
|
||||
st.prices.set('price_hosting', price('price_hosting', config.products.hosting.lookupKey, config.products.hosting.amountCents))
|
||||
st.prices.set('price_wartung', price('price_wartung', config.products.wartung.lookupKey, config.products.wartung.amountCents))
|
||||
st.prices.set('price_mailStorage', price('price_mailStorage', config.mailStorage.lookupKey, config.mailStorage.amountCents))
|
||||
|
||||
const nowUnix = () => Math.floor(Date.now() / 1000)
|
||||
const K12_SUBJECT = 'Ihr Wechsel ins WEBklar Wartungs-Abo – Bestätigung'
|
||||
const CARD = { id: 'pm_card_visa', object: 'payment_method', type: 'card' }
|
||||
const sampleValues = (tpl) => Object.fromEntries(tpl.placeholders.map((p) => [p, `Wert-${p}`]))
|
||||
const switchInvoice = (overrides = {}) => ({ id: 'in_wechsel', object: 'invoice', status: 'paid', amount_due: 4100, billing_reason: 'subscription_update', hosted_invoice_url: 'https://invoice.stripe.test/i/in_wechsel', ...overrides })
|
||||
|
||||
async function clearEvents(customerId) {
|
||||
for (const e of await listContractEvents(customerId)) await deleteDocument(config.collections.contractEvents, e.$id)
|
||||
}
|
||||
async function resetHosting() {
|
||||
await clearEvents('c1')
|
||||
aw.seed('subscriptions', { ...hostingDoc })
|
||||
st.subscriptions.set('sub_h', stripeSubscription({ id: 'sub_h', customerId: 'c1', productKey: 'hosting', default_payment_method: CARD }))
|
||||
st.nextSubscriptionUpdate = null
|
||||
mails.sent.length = 0
|
||||
}
|
||||
|
||||
test('Vorlage K12: der Absatz „ausdrücklich verlangt“ hängt am Block sofortverlangen', () => {
|
||||
const tpl = loadTemplate('K12')
|
||||
const werte = sampleValues(tpl)
|
||||
assert.ok(tpl.blocks.includes('sofortverlangen'))
|
||||
assert.match(renderMail('K12', werte, { sofortverlangen: true }).text, /Sie haben ausdrücklich verlangt, dass wir vor Ablauf der Widerrufsfrist mit dem Wartungs-Abo beginnen/)
|
||||
assert.doesNotMatch(renderMail('K12', werte, {}).text, /ausdrücklich verlangt|Wertersatz/)
|
||||
assert.match(renderMail('K12', werte, {}).text, /haben wir am Wert-zustimmung_zeitpunkt Uhr erhalten\./, 'die Zustimmungszeile bleibt')
|
||||
assert.deepEqual(renderMail('K12', werte, { sofortverlangen: true }).problems, [])
|
||||
assert.deepEqual(renderMail('K12', werte, {}).problems, [])
|
||||
})
|
||||
|
||||
test('K12 im Betrieb-Wechsel ohne den Satz, im Privat-Wechsel und in der alten Ansicht mit dem Satz', async () => {
|
||||
const text = async (consentExtra) => {
|
||||
await resetHosting()
|
||||
st.nextSubscriptionUpdate = { latest_invoice: switchInvoice() }
|
||||
const { earlyStartConsentAt: _x, ...ohne } = consent
|
||||
await switchToWartung('c1', { ...ohne, ...consentExtra }, nowUnix())
|
||||
return mails.sent.find((m) => m.subject === K12_SUBJECT).text
|
||||
}
|
||||
assert.doesNotMatch(await text({ kundenart: 'unternehmen' }), /ausdrücklich verlangt|Wertersatz/)
|
||||
assert.match(await text({ kundenart: 'privat', earlyStartConsentAt: consent.consentAt }), /Sie haben ausdrücklich verlangt/)
|
||||
assert.match(await text({ earlyStartConsentAt: consent.consentAt }), /Sie haben ausdrücklich verlangt/)
|
||||
})
|
||||
|
||||
// Abo-IDs sind 28 Zeichen wie bei Stripe (sub_ + 24)
|
||||
const SUB_NEW = 'sub_1SD6vPRxAbCdEfGhIjKlMnOp'
|
||||
const checkoutCompleted = (subscriptionId, metadata = {}) => ({
|
||||
id: `evt_${subscriptionId}`,
|
||||
object: 'event',
|
||||
type: 'checkout.session.completed',
|
||||
created: Math.floor(Date.now() / 1000),
|
||||
data: {
|
||||
object: {
|
||||
id: `cs_${subscriptionId}`, object: 'checkout.session', mode: 'subscription', subscription: subscriptionId, customer: 'cus_c3',
|
||||
customer_details: { email: 'k3@example.invalid', name: 'Kunde Drei' },
|
||||
metadata: { webklarCustomerId: 'c3', productKey: 'wartung', ...metadata },
|
||||
},
|
||||
},
|
||||
})
|
||||
async function cleanupWebhook(subscriptionId) {
|
||||
await clearEvents('c3')
|
||||
await deleteDocument(config.collections.subscriptions, subscriptionId).catch(() => {})
|
||||
}
|
||||
|
||||
test('K01: Fassung 6 ohne Zeitstempel (Betrieb) ohne „ausdrücklich verlangt“, mit Zeitstempel und in Fassung 5 mit dem Satz', async () => {
|
||||
const k01 = async (metadata) => {
|
||||
st.subscriptions.set(SUB_NEW, stripeSubscription({ id: SUB_NEW, customerId: 'c3', productKey: 'wartung', metadata }))
|
||||
mails.sent.length = 0
|
||||
try {
|
||||
assert.equal((await postWebhook(checkoutCompleted(SUB_NEW))).status, 200)
|
||||
return mails.sent.find((m) => m.subject.includes('Vertragsbestätigung')).text
|
||||
} finally {
|
||||
await cleanupWebhook(SUB_NEW)
|
||||
}
|
||||
}
|
||||
assert.doesNotMatch(await k01({ termsVersion: config.abo.termsVersionNeu, startChoice: 'sofort', earlyStartConsentAt: '' }), /ausdrücklich verlangt/)
|
||||
assert.match(await k01({ termsVersion: config.abo.termsVersionNeu, startChoice: 'sofort', earlyStartConsentAt: new Date().toISOString() }), /ausdrücklich verlangt/)
|
||||
assert.match(await k01({ termsVersion: config.abo.termsVersion, startChoice: 'sofort', earlyStartConsentAt: '' }), /ausdrücklich verlangt/)
|
||||
})
|
||||
Reference in new issue
Block a user