Kundenansicht neu E-Fix F5: Fassung 6 ohne PDF behauptet keinen Anhang, das Team bekommt den Hinweis
Die PDFs der Fassung 6 entstehen erst nach der Freigabe. Bis dahin gingen K01, K12 und K13 ohne Anhang raus, sagten aber "im Anhang" bzw. "beigefügt", und das Team erfuhr es nicht (nur K38/T24 hatten dafür den Block anhang_fehlt). - Neuer Helfer vertragsAnhang.js: lädt das PDF der zugestimmten Fassung und meldet fehlt nur bei Fassung 6 ohne lesbare Datei. - K01, K12, K13: Block anhang (Anhangsaussagen) und ohne_anhang (Satz, dass die Unterlagen gesondert kommen). - T02, T12, T13: Block anhang_fehlt "Unterlagen von Hand nachsenden" (T12 auch beim späteren Wirksamwerden, T13 auch ohne Aufgabe). - Alte Fassungen unverändert: Hash-Pins auf die Wiedergabe der Vorlagen vor der Änderung, Anhang und Texte wie bisher. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
9c04f806eb
commit
72b5ac5265
12 files changed
+362
-66
No files matched your search
@@ -0,0 +1,237 @@
|
||||
import { test, after } from 'node:test'
|
||||
import assert from 'node:assert/strict'
|
||||
import { createHash } from 'node:crypto'
|
||||
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'
|
||||
|
||||
// Abschlussprüfung F5: Fassung 6 ohne PDF. Fehlt der Anhang, behaupten K01, K12 und K13 kein „im Anhang“, und das Team bekommt in T02, T12 bzw. T13
|
||||
// den Block anhang_fehlt (Muster K38/T24). Alte Fassungen bleiben unverändert (Hash-Pins auf die Wiedergabe der alten Vorlagen).
|
||||
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 { changeStorage } = await import('../server/services/mailStorage.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 NEU = config.abo.termsVersionNeu
|
||||
const MIT_PDF = '2099-01-01-v4' // eine Fassung, deren PDF im Repo liegt (Archiv v4), um „Fassung 6 mit PDF“ nachzustellen
|
||||
const nowUnix = () => Math.floor(Date.now() / 1000)
|
||||
const sampleValues = (tpl) => Object.fromEntries(tpl.placeholders.map((p) => [p, `Wert-${p}`]))
|
||||
const sha = (html) => createHash('sha256').update(html).digest('hex')
|
||||
const HINWEIS = 'Unterlagen von Hand nachsenden'
|
||||
|
||||
/** Fassung 6 ist die neue Fassung dieses Laufs: mit termsVersionNeu auf eine Fassung mit PDF zeigt die Neu-Fassung eine vorhandene Datei. */
|
||||
async function mitNeuFassung(fassung, fn) {
|
||||
const vorher = config.abo.termsVersionNeu
|
||||
config.abo.termsVersionNeu = fassung
|
||||
try {
|
||||
return await fn()
|
||||
} finally {
|
||||
config.abo.termsVersionNeu = vorher
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- Vorlagen
|
||||
test('Vorlagen: K01, K12 und K13 kennen anhang und ohne_anhang, T02, T12 und T13 den Block anhang_fehlt', () => {
|
||||
for (const id of ['K01', 'K12', 'K13']) assert.deepEqual(['anhang', 'ohne_anhang'].filter((b) => !loadTemplate(id).blocks.includes(b)), [], id)
|
||||
for (const id of ['T02', 'T12', 'T13']) assert.ok(loadTemplate(id).blocks.includes('anhang_fehlt'), id)
|
||||
// ohne Anhang keine Behauptung „im Anhang“ / „beigefügt“, dafür der Satz, dass die Unterlagen gesondert kommen
|
||||
const K13_BESTELLUNG = { plus: true, bestellung: true }
|
||||
for (const [id, blocks] of [['K01', { wartung: true, sofortbeginn: true }], ['K12', {}], ['K13', K13_BESTELLUNG]]) {
|
||||
const ohne = renderMail(id, sampleValues(loadTemplate(id)), { ...blocks, ohne_anhang: true })
|
||||
assert.doesNotMatch(ohne.text, /Anhang|beigefügt/i, `${id} ohne Anhang`)
|
||||
assert.match(ohne.text, /senden wir Ihnen gesondert zu/, id)
|
||||
assert.deepEqual(ohne.problems, [], id)
|
||||
const mit = renderMail(id, sampleValues(loadTemplate(id)), { ...blocks, anhang: true })
|
||||
assert.match(mit.text, /im Anhang|beigefügten/, `${id} mit Anhang`)
|
||||
assert.doesNotMatch(mit.text, /gesondert zu/, id)
|
||||
}
|
||||
for (const id of ['T02', 'T12', 'T13']) {
|
||||
const mit = renderMail(id, sampleValues(loadTemplate(id)), { anhang_fehlt: true })
|
||||
assert.match(mit.text, new RegExp(HINWEIS), id)
|
||||
assert.match(mit.text, /nicht mit der Bestätigung beim Kunden angekommen/, id)
|
||||
assert.doesNotMatch(renderMail(id, sampleValues(loadTemplate(id)), {}).text, new RegExp(HINWEIS), id)
|
||||
}
|
||||
})
|
||||
|
||||
// Hash der Wiedergabe der Vorlagen vor der Änderung (Stand kn-p7 plus P8-Nachträge, ohne anhang-Blöcke): die alten Fassungen bleiben bytegleich
|
||||
const ALT = [
|
||||
['K01', {"hosting": true, "sofortbeginn": true}, 'ea5fed3076d4bf6c4f5aa7042d20d61c1d90d11716f99811e439df09c95abd56'],
|
||||
['K01', {"wartung": true, "beginn_nach_widerrufsfrist": true, "angebot": true}, '434d4945815af9e8df98039184e09058b992c32f1f7a21844b25923be2130aca'],
|
||||
['K01', {"wartung_v3": true, "sofortbeginn": true}, '4a5a3252ad7ea5c5eda35b42480f95611a4cb5648e9a847afc6720692240d729'],
|
||||
['K12', {"zahlung_offen": true, "zusatzspeicher": true, "sofortverlangen": true}, '8c18e9a2455e28ec5467fb68dcdfe9b66afe9cc676ef16cc84281a4b2d97caf2'],
|
||||
['K12', {"lastschrift": true}, '9731b26f4043f29537e289edf7b00d4d024522c6bafb9166d3a0b6289e592963'],
|
||||
['K12', {}, '76a6f5f1f350f80a938828ce2cd1d84305aca2251427e2ad0df7bb550dc18ff7'],
|
||||
['K13', {"plus": true, "bestellung": true}, 'b01d4f6a30f562ccee3739f8f5b77bb9a660a61165366cd3d294a627ccfdc8c8'],
|
||||
['K13', {"plus_bezahlt": true, "bestellung": true}, '7a41e74fe6bf45a33bb6e9dd35d29f6995b8995961e3b6905ed5ba45e19b0e51'],
|
||||
['K13', {"minus": true}, 'a82497427b0d7af96aadd380974ce5e73930ec2c9a7f5b6357f5f13f8190d109'],
|
||||
['T02', {"angebot": true, "angebot_fehler": true, "nachweis_fehlt": true}, '438a623fb53046b34930a30110fa35d3c08c6f27ff84af21466426496202a441'],
|
||||
['T02', {}, '386199538e7a59eb09b41511f4cab3924c36cacdbbdba281af45b2fa86158755'],
|
||||
['T12', {"wirksam": true, "nachweis_fehlt": true}, '3777c2edc646e53b5b63280132e0958e31dba5d084848244525882a9b2fb1d07'],
|
||||
['T12', {"lastschrift": true, "gescheitert": true}, '56e1c70e82d260b6c62788fbed5503d2e4e6c6fff1046281b7e76261ced5f1c9'],
|
||||
['T12', {}, '928f6ee5118da82fce612d77f6dab22be4c3b0aefc736e64668a9d24b69da98a'],
|
||||
['T13', {"einrichten": true, "nachweis_fehlt": true}, '2f5543fec1ecdc7726931967b164d42386a9d32f0f062e8d5770002958c33a72'],
|
||||
['T13', {"periodenende": true, "teilweise": true}, '44fa59476f1edb46f977500b1d8ebed7f07205ca2f6087609c2602e15f10eaeb'],
|
||||
['T13', {}, '793af7c1cb98df24d914d1a5bf3330ace1751a2794713045b78a9ac2a93f1a9f'],
|
||||
]
|
||||
test('Alte Fassungen: die Wiedergabe der Vorlagen bleibt bytegleich (K mit anhang, T ohne anhang_fehlt)', () => {
|
||||
for (const [id, blocks, soll] of ALT) {
|
||||
const mitAnhang = id.startsWith('K') ? { ...blocks, anhang: true } : blocks
|
||||
assert.equal(sha(renderMail(id, sampleValues(loadTemplate(id)), mitAnhang).html), soll, `${id} ${JSON.stringify(blocks)}`)
|
||||
}
|
||||
})
|
||||
|
||||
// ---------------------------------------------------------------- K01 und T02
|
||||
const SUB_NEW = 'sub_1SD6vPRxAbCdEfGhIjKlMnOp'
|
||||
const checkoutCompleted = (subscriptionId, metadata = {}) => ({
|
||||
id: `evt_${subscriptionId}`, object: 'event', type: 'checkout.session.completed', created: nowUnix(),
|
||||
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 clearEvents(customerId) {
|
||||
for (const e of await listContractEvents(customerId)) await deleteDocument(config.collections.contractEvents, e.$id)
|
||||
}
|
||||
async function k01(termsVersion) {
|
||||
st.subscriptions.set(SUB_NEW, stripeSubscription({ id: SUB_NEW, customerId: 'c3', productKey: 'wartung', metadata: { termsVersion, startChoice: 'sofort', earlyStartConsentAt: new Date().toISOString() } }))
|
||||
mails.sent.length = 0
|
||||
try {
|
||||
assert.equal((await postWebhook(checkoutCompleted(SUB_NEW))).status, 200)
|
||||
return { kunde: mails.sent.find((m) => m.subject.includes('Vertragsbestätigung')), team: mails.sent.find((m) => m.subject.startsWith('[Abo] Neues')) }
|
||||
} finally {
|
||||
await clearEvents('c3')
|
||||
await deleteDocument(config.collections.subscriptions, SUB_NEW).catch(() => {})
|
||||
}
|
||||
}
|
||||
|
||||
test('K01: Fassung 6 ohne PDF behauptet keinen Anhang, T02 sagt es dem Team', async () => {
|
||||
const { kunde, team } = await k01(NEU)
|
||||
assert.equal(kunde.attachments.length, 0)
|
||||
assert.doesNotMatch(kunde.text, /Anhang|beigefügt/i)
|
||||
assert.match(kunde.text, /senden wir Ihnen gesondert zu/)
|
||||
assert.match(team.text, new RegExp(HINWEIS))
|
||||
})
|
||||
test('K01: Fassung 6 mit PDF und alte Fassung wie bisher (Anhang, kein Hinweis)', async () => {
|
||||
for (const [name, fassung, neu] of [['Fassung 6 mit PDF', MIT_PDF, MIT_PDF], ['Fassung 5', config.abo.termsVersion, NEU]]) {
|
||||
const { kunde, team } = await mitNeuFassung(neu, () => k01(fassung))
|
||||
assert.equal(kunde.attachments.length, 1, name)
|
||||
assert.match(kunde.text, /im Anhang/, name)
|
||||
assert.doesNotMatch(kunde.text, /gesondert zu/, name)
|
||||
assert.doesNotMatch(team.text, new RegExp(HINWEIS), name)
|
||||
}
|
||||
})
|
||||
|
||||
// ---------------------------------------------------------------- K12 und T12
|
||||
const CARD = { id: 'pm_card_visa', object: 'payment_method', type: 'card' }
|
||||
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 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
|
||||
}
|
||||
async function k12(termsVersion) {
|
||||
await resetHosting()
|
||||
st.nextSubscriptionUpdate = { latest_invoice: switchInvoice() }
|
||||
await switchToWartung('c1', { ...consent, termsVersion }, nowUnix())
|
||||
return { kunde: mails.sent.find((m) => m.subject === 'Ihr Wechsel ins WEBklar Wartungs-Abo – Bestätigung'), team: mails.sent.find((m) => m.subject.startsWith('[Abo] Wechsel ins Wartungs-Abo')) }
|
||||
}
|
||||
test('K12: Fassung 6 ohne PDF behauptet keinen Anhang, T12 sagt es dem Team; mit PDF und alte Fassung wie bisher', async () => {
|
||||
const ohne = await k12(NEU)
|
||||
assert.equal(ohne.kunde.attachments.length, 0)
|
||||
assert.doesNotMatch(ohne.kunde.text, /Anhang|beigefügt/i)
|
||||
assert.match(ohne.kunde.text, /senden wir Ihnen gesondert zu/)
|
||||
assert.match(ohne.team.text, new RegExp(HINWEIS))
|
||||
for (const [name, fassung, neu] of [['Fassung 6 mit PDF', MIT_PDF, MIT_PDF], ['Fassung 5', config.abo.termsVersion, NEU]]) {
|
||||
const r = await mitNeuFassung(neu, () => k12(fassung))
|
||||
assert.equal(r.kunde.attachments.length, 1, name)
|
||||
assert.match(r.kunde.text, /im Anhang/, name)
|
||||
assert.doesNotMatch(r.team.text, new RegExp(HINWEIS), name)
|
||||
}
|
||||
})
|
||||
|
||||
// ---------------------------------------------------------------- K13 und T13
|
||||
async function resetSubH({ units, paidUnits }) {
|
||||
await clearEvents('c1')
|
||||
mails.sent.length = 0
|
||||
aw.seed('subscriptions', { ...hostingDoc, storageUnits: units, storagePaidUnits: paidUnits, storagePaidPeriodEnd: hostingDoc.currentPeriodEnd })
|
||||
st.subscriptions.set('sub_h', stripeSubscription({ id: 'sub_h', customerId: 'c1', productKey: 'hosting', storageUnits: units }))
|
||||
}
|
||||
async function k13({ units, paidUnits, ziel, termsVersion }) {
|
||||
await resetSubH({ units, paidUnits })
|
||||
await changeStorage('c1', ziel, { ...consent, termsVersion })
|
||||
return { kunde: mails.sent.find((m) => m.subject === 'Ihr E-Mail-Zusatzspeicher – Bestätigung'), team: mails.sent.find((m) => m.subject.startsWith('[Speicher]')) }
|
||||
}
|
||||
test('K13: Fassung 6 ohne PDF behauptet keinen Anhang, T13 sagt es dem Team (auch ohne Aufgabe); mit PDF und alte Fassung wie bisher', async () => {
|
||||
const ohne = await k13({ units: 0, paidUnits: 0, ziel: 2, termsVersion: NEU })
|
||||
assert.equal(ohne.kunde.attachments.length, 0)
|
||||
assert.doesNotMatch(ohne.kunde.text, /Anhang|beigefügt/i)
|
||||
assert.match(ohne.kunde.text, /senden wir Ihnen gesondert zu/)
|
||||
assert.match(ohne.team.text, new RegExp(HINWEIS))
|
||||
// Plus nur bis zur schon bezahlten Menge: keine Aufgabe, aber die Unterlagen müssen nachgesendet werden
|
||||
const bezahlt = await k13({ units: 1, paidUnits: 3, ziel: 3, termsVersion: NEU })
|
||||
assert.equal(bezahlt.kunde.attachments.length, 0)
|
||||
assert.ok(bezahlt.team, 'T13 geht auch ohne Aufgabe raus, wenn der Anhang fehlt')
|
||||
assert.match(bezahlt.team.text, new RegExp(HINWEIS))
|
||||
for (const [name, fassung, neu] of [['Fassung 6 mit PDF', MIT_PDF, MIT_PDF], ['Fassung 5', config.abo.termsVersion, NEU]]) {
|
||||
const r = await mitNeuFassung(neu, () => k13({ units: 0, paidUnits: 0, ziel: 2, termsVersion: fassung }))
|
||||
assert.equal(r.kunde.attachments.length, 1, name)
|
||||
assert.match(r.kunde.text, /beigefügten Vertragsunterlagen/, name)
|
||||
assert.doesNotMatch(r.team.text, new RegExp(HINWEIS), name)
|
||||
}
|
||||
// Verringerung: nie ein Anhang, nie ein Hinweis
|
||||
const minus = await k13({ units: 3, paidUnits: 3, ziel: 1, termsVersion: NEU })
|
||||
assert.equal(minus.kunde.attachments.length, 0)
|
||||
assert.doesNotMatch(minus.team.text, new RegExp(HINWEIS))
|
||||
})
|
||||
|
||||
// Karte mit Bestätigung bei der Bank: K12 geht beim Klick, T12 "wirksam" erst mit pending_update_applied; auch dieses T12 sagt, dass die PDFs fehlen
|
||||
test('T12 beim späteren Wirksamwerden (Karte, pending_update_applied) trägt anhang_fehlt, solange die PDFs der Fassung 6 fehlen', async () => {
|
||||
await resetHosting()
|
||||
const nowU = nowUnix()
|
||||
st.nextSubscriptionUpdate = {
|
||||
pending_update: { expires_at: nowU + 23 * 3600, billing_cycle_anchor: nowU, subscription_items: [], trial_end: null, trial_from_plan: null },
|
||||
latest_invoice: switchInvoice({ status: 'open', hosted_invoice_url: 'https://pay.example/karte' }),
|
||||
}
|
||||
await switchToWartung('c1', { ...consent, termsVersion: NEU }, nowU)
|
||||
assert.ok(mails.sent.find((m) => m.subject === 'Ihr Wechsel ins WEBklar Wartungs-Abo – Bestätigung'), 'K12 ging beim Klick raus')
|
||||
assert.equal(mails.sent.filter((m) => m.subject.startsWith('[Abo] Wechsel ins Wartungs-Abo')).length, 0, 'T12 wartet auf die Zahlung')
|
||||
st.applyPendingUpdate('sub_h')
|
||||
const res = await postWebhook({ id: 'evt_pua', object: 'event', type: 'customer.subscription.pending_update_applied', created: nowU, data: { object: { id: 'sub_h', object: 'subscription' } } })
|
||||
assert.equal(res.status, 200, JSON.stringify(res.body))
|
||||
const t12 = mails.sent.filter((m) => m.subject.startsWith('[Abo] Wechsel ins Wartungs-Abo'))
|
||||
assert.equal(t12.length, 1)
|
||||
assert.match(t12[0].text, new RegExp(HINWEIS))
|
||||
})
|
||||
@@ -260,11 +260,11 @@ test('Werte werden HTML-sicher eingesetzt, Zeilenumbrüche werden <br>', () => {
|
||||
|
||||
test('optionale Blöcke: nur eingeschaltete erscheinen', () => {
|
||||
const values = { name: 'Max', produkt: 'Wartungs-Abo', preis: '50,00 € / Monat', angebot_text: 'Erste 2 Monate je 25,00 €', vertragsschluss: '01.10.2026', leistungsbeginn: '15.10.2026', mindestlaufzeit_bis: '15.10.2027', bedingungen_version: 'v3', zustimmung_zeitpunkt: '01.10.2026, 10:00' }
|
||||
const early = renderMail('K01', values, { angebot: false, sofortbeginn: true, beginn_nach_widerrufsfrist: false })
|
||||
const early = renderMail('K01', values, { angebot: false, sofortbeginn: true, beginn_nach_widerrufsfrist: false, anhang: true })
|
||||
assert.doesNotMatch(early.html, /Ihr Angebot:/)
|
||||
assert.match(early.html, /Sie haben ausdrücklich verlangt/)
|
||||
assert.doesNotMatch(early.html, /erst nach Ablauf der Widerrufsfrist/)
|
||||
const late = renderMail('K01', values, { angebot: true, sofortbeginn: false, beginn_nach_widerrufsfrist: true })
|
||||
const late = renderMail('K01', values, { angebot: true, sofortbeginn: false, beginn_nach_widerrufsfrist: true, anhang: true })
|
||||
assert.match(late.html, /Ihr Angebot:<\/strong> Erste 2 Monate je 25,00 € \(wie vereinbart\)/)
|
||||
assert.doesNotMatch(late.html, /Sie haben ausdrücklich verlangt/)
|
||||
assert.match(late.html, /Leistungsbeginn und erste Abbuchung: 15\.10\.2026\./)
|
||||
@@ -298,7 +298,7 @@ test('Textfassung K01: alle Vertragsangaben lesbar', () => {
|
||||
const mail = renderMail(
|
||||
'K01',
|
||||
{ name: 'Erika Musterfrau', produkt: 'Wartungs-Abo', preis: '50,00 € / Monat', angebot_text: '', vertragsschluss: '01.10.2026', leistungsbeginn: '01.10.2026', mindestlaufzeit_bis: '01.10.2027', bedingungen_version: '2026-09-25-v3', zustimmung_zeitpunkt: '01.10.2026, 10:07' },
|
||||
{ sofortbeginn: true, wartung: true }
|
||||
{ sofortbeginn: true, wartung: true, anhang: true }
|
||||
)
|
||||
assert.deepEqual(mail.problems, [])
|
||||
const t = mail.text
|
||||
@@ -373,7 +373,7 @@ test('K12: Block zahlung_offen wörtlich, Block lastschrift mit dem Satz aus §
|
||||
assert.match(sepa.text, /Wird die Lastschrift nicht eingelöst, gilt der Wechsel als nicht erfolgt/)
|
||||
assert.match(sepa.text, /Ihr Abbuchungstag bleibt der Wechseltag/)
|
||||
assert.doesNotMatch(sepa.text, /sobald die Zahlung bestätigt ist/)
|
||||
const plain = renderMail('K12', values, {})
|
||||
const plain = renderMail('K12', values, { anhang: true }) // Vertragsunterlagen hängen an (F5: ohne PDF der Fassung 6 stattdessen ohne_anhang)
|
||||
assert.doesNotMatch(plain.text, /sobald die Zahlung bestätigt ist|Wird die Lastschrift nicht eingelöst/)
|
||||
// Vertragsbestaetigung: Preis mit § 19 UStG, Mindestlaufzeit, Unterlagen, Zustimmung zum Sofortbeginn
|
||||
for (const text of ['gemäß § 19 UStG ohne Umsatzsteuer', 'Mindestlaufzeit 12 Monate bis Wert-mindestlaufzeit_bis.', 'Widerrufsbelehrung mit Muster-Widerrufsformular']) {
|
||||
@@ -406,22 +406,22 @@ test('K13, T13: Betreff, Platzhalter und Blöcke des Zusatzspeichers', () => {
|
||||
assert.deepEqual(loadTemplate('K13').placeholders, ['name', 'pakete', 'gesamt_gb', 'monatspreis_zusatz', 'wirksam_ab'])
|
||||
// Fix 2 (3): plus = Einrichtung mit anteiliger Berechnung, plus_bezahlt = Plus bis zur schon bezahlten Menge,
|
||||
// bestellung = Unterlagen und Widerruf (bei beiden), minus = Verringerung zum Periodenende
|
||||
assert.deepEqual(loadTemplate('K13').blocks, ['plus', 'plus_bezahlt', 'bestellung', 'minus'])
|
||||
assert.deepEqual(loadTemplate('K13').blocks, ['plus', 'plus_bezahlt', 'bestellung', 'minus', 'anhang', 'ohne_anhang'])
|
||||
assert.equal(loadTemplate('T13').subject, '[Speicher] {{aktion}}: {{email}}')
|
||||
for (const p of ['aktion', 'email', 'name', 'stripe_abo_id', 'postfaecher_hinweis', 'neue_groesse_gb', 'pakete', 'faellig']) {
|
||||
assert.ok(loadTemplate('T13').placeholders.includes(p), p)
|
||||
}
|
||||
assert.deepEqual([...loadTemplate('T13').blocks].sort(), ['einrichten', 'nachweis_fehlt', 'periodenende', 'teilweise'])
|
||||
assert.deepEqual([...loadTemplate('T13').blocks].sort(), ['anhang_fehlt', 'einrichten', 'nachweis_fehlt', 'periodenende', 'teilweise'])
|
||||
|
||||
const values = sampleValues(loadTemplate('K13'))
|
||||
const plus = renderMail('K13', values, { plus: true, bestellung: true })
|
||||
const plus = renderMail('K13', values, { plus: true, bestellung: true, anhang: true })
|
||||
assert.deepEqual(plus.problems, [])
|
||||
assert.match(plus.text, /gemäß § 19 UStG ohne Umsatzsteuer/)
|
||||
assert.match(plus.text, /wird eingerichtet/)
|
||||
assert.match(plus.text, /14 Tagen widerrufen/)
|
||||
assert.match(plus.text, /Vertragsunterlagen im Anhang/)
|
||||
assert.doesNotMatch(plus.text, /ohne anteilige Erstattung|keine zusätzlichen Kosten/)
|
||||
const paid = renderMail('K13', values, { plus_bezahlt: true, bestellung: true })
|
||||
const paid = renderMail('K13', values, { plus_bezahlt: true, bestellung: true, anhang: true })
|
||||
assert.ok(paid.text.includes('Die Pakete sind für den laufenden Monat schon bezahlt; es entstehen keine zusätzlichen Kosten. Ab dem nächsten Abrechnungsmonat gelten Wert-pakete Pakete.'))
|
||||
assert.match(paid.text, /14 Tagen widerrufen/)
|
||||
assert.match(paid.text, /Vertragsunterlagen im Anhang/)
|
||||
|
||||
Reference in new issue
Block a user