From fa79e6e10c498f178d0424b64e5a53adbc047d90 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 16 Oct 2026 22:06:36 +0000 Subject: [PATCH] Kundenansicht neu E-Fix F1 (Nachtrag): Wechsel mit gebuchtem Zusatzspeicher passt auf 375x667 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mit gebuchtem Zusatzspeicher (eine Block-Zeile mehr) maß der Wechsel 598 px gegen 558 nutzbare. Jetzt steckt der Zusatzspeicher im Preis ("52,00 € pro Monat mit 2 Paketen Zusatzspeicher (+10 GB)") und die gutgeschriebenen Tage in "Fällig"; die Einzelposten stehen ausführlich unter dem Knopf. Gemessen auf 375x667 (Blockanfang bis Knopfunterkante, nutzbar 558 px): Wechsel Betrieb 448, Wechsel privat mit Häkchen 516, mit Zusatzspeicher 536 px. Co-Authored-By: Claude Sonnet 5.5 --- public/neu/ansicht-wechsel.js | 26 ++++++++++++++++---------- test/knAnsichtWechsel.test.js | 16 ++++++++-------- 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/public/neu/ansicht-wechsel.js b/public/neu/ansicht-wechsel.js index d18f9e2..0be250a 100644 --- a/public/neu/ansicht-wechsel.js +++ b/public/neu/ansicht-wechsel.js @@ -77,20 +77,23 @@ export async function zeigeWechsel(wurzel, { route, me, nav, daten } = {}) { const lauf = { busy: false, preview: null, error: '', loading: true, token: 0, early: false, fehler: '', fehlerKlasse: null, zeichne: null } aktiv = lauf - /** Zeilen des Blocks aus der Vorschau des Servers, knapp: Leistung, Preis, Zusatzspeicher, Gutschrift, Fällig (mit Abbuchungstag), Laufzeit, Beginn. */ + const paketText = `${units} Paket${units === 1 ? '' : 'e'}` + const speicherGb = units * (Number(mail.gbPerUnit) || 0) + + /** + * Zeilen des Blocks aus der Vorschau des Servers, knapp: Leistung, Preis (mit gebuchtem Zusatzspeicher), Fällig (mit der Gutschrift und dem Abbuchungstag), + * Laufzeit, Beginn. Die Einzelposten stehen ausführlich unter dem Knopf (einzelheitenVon); so passt der Block auch mit Zusatzspeicher in 375 x 667. + */ const zeilenVon = (p) => { const monthly = Number.isFinite(Number(p.monthlyCents)) && p.monthlyCents != null ? Number(p.monthlyCents) : wartung.amountCents const tag = berlinTag(p.nextChargeAt) + const gutschrift = (Number(p.creditCents) || 0) > 0 ? ` (nach Gutschrift von ${fmtEuro(p.creditCents / 100)} für nicht genutzte Tage des Hosting-Abos)` : '' return [ { label: 'Leistung', text: 'Wartungs-Abo statt Hosting-Abo', link: { text: 'Leistungen ansehen', href: leistungLink(T.wechsel.linkzeile, 'wartung') } }, - { label: 'Preis', text: `${fmtEuro(monthly / 100)} pro Monat (Gesamtpreis, ${UST})` }, - ...(units > 0 - ? [{ label: 'Zusatzspeicher', text: `${units} Paket${units === 1 ? '' : 'e'} (+${units * (Number(mail.gbPerUnit) || 0)} GB) bleiben gebucht, insgesamt ${fmtEuro((monthly + units * unitCents) / 100)} pro Monat` }] - : []), - ...((Number(p.creditCents) || 0) > 0 - ? [{ label: 'Gutschrift', text: `−${fmtEuro(p.creditCents / 100)} für nicht genutzte Tage des Hosting-Abos` }] - : []), - { label: 'Fällig', text: `heute ${fmtEuro(p.amountDueCents / 100)}; danach ab ${fmtDatum(p.nextChargeAt)}${tag ? ` jeweils am ${tag.t}.` : ''}` }, + { label: 'Preis', text: units > 0 + ? `${fmtEuro((monthly + units * unitCents) / 100)} pro Monat mit ${paketText} Zusatzspeicher (+${speicherGb} GB) (Gesamtpreis, ${UST})` + : `${fmtEuro(monthly / 100)} pro Monat (Gesamtpreis, ${UST})` }, + { label: 'Fällig', text: `heute ${fmtEuro(p.amountDueCents / 100)}${gutschrift}; danach ab ${fmtDatum(p.nextChargeAt)}${tag ? ` jeweils am ${tag.t}.` : ''}` }, { label: 'Laufzeit', text: `Mindestlaufzeit bis ${fmtDatum(p.minTermEnd)} (12 Monate), danach monatlich kündbar` }, { label: 'Beginn', text: 'sofort mit der Zahlung; einen späteren Beginn gibt es nicht' }, ] @@ -102,7 +105,10 @@ export async function zeigeWechsel(wurzel, { route, me, nav, daten } = {}) { return [ { label: 'Leistung', text: 'Zusätzlich zum Hosting: Pflege deiner Website, beliebig viele Postfächer und 1 Stunde Arbeitszeit pro Monat. Das Hosting-Abo endet mit dem Wechsel im gegenseitigen Einvernehmen; Domain, Postfächer und gebuchter Speicher bleiben.' }, ...(units > 0 - ? [{ label: 'Zusatzspeicher', text: `${units} Paket${units === 1 ? '' : 'e'} (+${units * (Number(mail.gbPerUnit) || 0)} GB) bleiben gebucht: ${fmtEuro(units * unitCents / 100)} pro Monat zusätzlich (${UST})` }] + ? [{ label: 'Zusatzspeicher', text: `${paketText} (+${speicherGb} GB) bleiben gebucht: ${fmtEuro(units * unitCents / 100)} pro Monat zusätzlich (${UST})` }] + : []), + ...((Number(p.creditCents) || 0) > 0 + ? [{ label: 'Gutschrift für nicht genutzte Tage', text: `−${fmtEuro(p.creditCents / 100)} aus dem bereits bezahlten Hosting-Abo (${UST})` }] : []), { label: 'Heute fällig', text: `${fmtEuro(p.amountDueCents / 100)} (${UST})` }, { label: 'Neuer Abbuchungstag', text: `${tag ? `Ab dem Wechsel jeweils am ${tag.t}. eines Monats; ` : ''}nächste Abbuchung am ${fmtDatum(p.nextChargeAt)}` }, diff --git a/test/knAnsichtWechsel.test.js b/test/knAnsichtWechsel.test.js index 73f3321..0f0a798 100644 --- a/test/knAnsichtWechsel.test.js +++ b/test/knAnsichtWechsel.test.js @@ -30,19 +30,19 @@ test('Betrieb: Block, Linkzeile, Knopf, kein Häkchen, Knopf nach der Vorschau f assert.deepEqual(reihe(fx, w), ['switch-block', 'switch-linkzeile', 'switch-error', 'switch-buy', 'switch-kundenart', 'switch-einzelheiten']) // Block über dem Knopf: knapp (F1); Leistung als eine Zeile mit Link auf die Leistungsbeschreibung B (Wartung) const zeilen = fx.alle(fx.finde(w, '#switch-block'), '.kn-block-zeile').map((z) => [fx.text(fx.finde(z, 'dt')), fx.text(fx.finde(z, 'dd'))]) - assert.deepEqual(zeilen.map(([l]) => l), ['Leistung', 'Preis', 'Zusatzspeicher', 'Gutschrift', 'Fällig', 'Laufzeit', 'Beginn']) + // Zusatzspeicher steckt im Preis (ein Block weniger über dem Knopf), die gutgeschriebenen Tage in „Fällig“ (F1: auch mit gebuchtem Speicher auf 375 x 667) + assert.deepEqual(zeilen.map(([l]) => l), ['Leistung', 'Preis', 'Fällig', 'Laufzeit', 'Beginn']) assert.deepEqual(zeilen[0], ['Leistung', 'Wartungs-Abo statt Hosting-Abo · Leistungen ansehen']) assert.equal(fx.finde(fx.finde(w, '#switch-block'), 'a').getAttribute('href'), `${TERMS_URL}#wartung`) - assert.ok(zeilen[2][1].includes('2 Pakete (+10 GB)')) - assert.ok(zeilen[3][1].startsWith('−15,00')) - assert.ok(zeilen[4][1].startsWith('heute 30,00')) - assert.equal(zeilen[5][1], 'Mindestlaufzeit bis 16.10.2027 (12 Monate), danach monatlich kündbar') - assert.ok(zeilen[6][1].startsWith('sofort mit der Zahlung')) - for (const [l, text] of zeilen) assert.ok(text.length <= 120, `${l}: ${text.length} Zeichen`) + assert.ok(zeilen[1][1].includes('2 Pakete Zusatzspeicher (+10 GB)') && zeilen[1][1].includes('gemäß § 19 UStG ohne Umsatzsteuer'), zeilen[1][1]) + assert.ok(zeilen[2][1].startsWith('heute 30,00') && zeilen[2][1].includes('Gutschrift von 15,00') && zeilen[2][1].includes('ab 16.11.2026'), zeilen[2][1]) + assert.equal(zeilen[3][1], 'Mindestlaufzeit bis 16.10.2027 (12 Monate), danach monatlich kündbar') + assert.ok(zeilen[4][1].startsWith('sofort mit der Zahlung')) + for (const [l, text] of zeilen) assert.ok(text.length <= 140, `${l}: ${text.length} Zeichen`) // unter dem Knopf: die ausführlichen Sätze, ohne Klappe assert.equal(fx.alle(w, '#switch-order > *').map((e) => e.id).filter(Boolean).at(-1), 'switch-einzelheiten') const ein = fx.text(fx.finde(w, '#switch-einzelheiten')) - for (const x of ['Hosting-Abo endet mit dem Wechsel im gegenseitigen Einvernehmen', 'Neuer Abbuchungstag', 'nächste Abbuchung am', 'Heute fällig', 'bei deiner Bank', 'Einen späteren Beginn gibt es nicht', '12 Monate ab dem Wechsel']) assert.ok(ein.includes(x), x) + for (const x of ['Hosting-Abo endet mit dem Wechsel im gegenseitigen Einvernehmen', 'Zusatzspeicher', '2 Pakete (+10 GB) bleiben gebucht', 'Gutschrift für nicht genutzte Tage', '−15,00', 'Neuer Abbuchungstag', 'nächste Abbuchung am', 'Heute fällig', 'bei deiner Bank', 'Einen späteren Beginn gibt es nicht', '12 Monate ab dem Wechsel']) assert.ok(ein.includes(x), x) assert.equal(fx.finde(w, '#switch-buy').textContent, 'Zahlungspflichtig bestellen') assert.equal(fx.finde(w, '#switch-buy').hasAttribute('disabled'), false) assert.equal(fx.alle(w, 'details, dialog, input[type="checkbox"]').length, 0)