Webshop: Funktionen-Karte mit Anfrage annehmen/ablehnen, Stripe-Stand, Kennzahlen und Rechtliches-Karten

Webshop als Funktion im Reiter Funktionen (Aktionen wie beim Terminplaner), Panel je Projekt mit Anfrage,
Entscheidung mit Begruendung, Stripe-Status und Zahlen; Karten Leistungsbeschreibung und AVV Webshop.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ClaudeandClaude Opus 5.5 committed 2026-10-05 08:47:19 +00:00
1 parent 4c3f67eadc
commit 0a2eab85d5
6 files changed
+347 -13

No files matched your search

+135 -1
View File
@@ -25,9 +25,20 @@ const {
featureBody,
speicherStatus,
K16_WARNUNG,
warenartLabel,
artikelzahlLabel,
anfrageStatus,
anfrageZeilen,
anfrageText,
stripeText,
stripeTon,
shopHatEintrag,
begruendungOk,
entscheidungBody,
entscheidungStatus,
} = await loadModule('src/lib/funktionenView.js')
test('FUNKTIONEN: News und Terminplaner mit den Bestätigungstexten', () => {
test('FUNKTIONEN: News, Terminplaner und Webshop mit den Bestätigungstexten', () => {
assert.deepEqual(FUNKTIONEN, [
{
key: 'news',
@@ -47,6 +58,16 @@ test('FUNKTIONEN: News und Terminplaner mit den Bestätigungstexten', () => {
ticket: 'Fehlendes Einrichtungs-Ticket neu anlegen?',
},
},
{
key: 'shop',
label: 'Webshop',
bestaetigen: {
activate: 'Webshop ohne Zahlung aktivieren?',
disable: 'Webshop abschalten? Auf der Website sind dann keine Bestellungen mehr möglich.',
abnahme: 'Webshop freischalten? Der Kunde bekommt die Mail „bereit“ und der Shop kann geöffnet werden.',
ticket: 'Fehlendes Einrichtungs-Ticket neu anlegen?',
},
},
])
})
@@ -470,3 +491,116 @@ test('speicherStatus: warnung true (K16 nicht gesendet) wird zur Warnung, sonst
assert.deepEqual(speicherStatus({ projects: [] }), { ok: true, text: 'Gespeichert.' })
assert.deepEqual(speicherStatus(undefined), { ok: true, text: 'Gespeichert.' })
})
test('aktionen: Webshop verhält sich wie der Terminplaner (ticketbasiert)', () => {
assert.deepEqual(aktionen('off', 'shop'), ['activate'])
assert.deepEqual(aktionen('disabled', 'shop'), ['activate'])
assert.deepEqual(aktionen('ordered', 'shop'), ['disable'])
assert.deepEqual(aktionen('active', 'shop'), ['disable'])
assert.deepEqual(aktionen('setup', 'shop'), ['abnahme', 'disable'])
assert.deepEqual(aktionen('setup', 'shop', { ticketMissing: true }), ['ticket', 'abnahme', 'disable'])
for (const state of ['off', 'ordered', 'active', 'disabled']) assert.deepEqual(aktionen(state, 'shop', { ticketMissing: true }), aktionen(state, 'shop'))
for (const action of aktionen('setup', 'shop', { ticketMissing: true })) assert.ok(FUNKTIONEN.find((f) => f.key === 'shop').bestaetigen[action], `Text für ${action}`)
})
test('siteKeyOf: auch der Webshop zeigt seinen Site-Key', () => {
assert.equal(siteKeyOf({ state: 'active', siteKey: ' abcdefghijklmnop ' }, 'shop'), 'abcdefghijklmnop')
assert.equal(siteKeyOf({ state: 'active' }, 'shop'), '')
})
test('warenartLabel und artikelzahlLabel: Beschriftungen, Unbekanntes bleibt sichtbar', () => {
assert.equal(warenartLabel('waren'), 'Waren')
assert.equal(warenartLabel('lebensmittel'), 'Lebensmittel')
assert.equal(warenartLabel('kleidung'), 'Kleidung')
assert.equal(warenartLabel('kunst'), 'Kunst/Handgemachtes')
assert.equal(warenartLabel('sonstiges'), 'Sonstiges')
assert.equal(warenartLabel('xyz'), 'xyz')
assert.equal(warenartLabel(undefined), '–')
assert.equal(warenartLabel('toString'), 'toString', 'kein Treffer über die Prototypkette')
assert.equal(artikelzahlLabel('bis20'), 'bis 20')
assert.equal(artikelzahlLabel('bis100'), 'bis 100')
assert.equal(artikelzahlLabel('mehr'), 'mehr als 100')
assert.equal(artikelzahlLabel(''), '–')
})
test('anfrageStatus: Ton und Beschriftung', () => {
assert.deepEqual(anfrageStatus('offen'), ['warn', 'Offen'])
assert.deepEqual(anfrageStatus('angenommen'), ['ok', 'Angenommen'])
assert.deepEqual(anfrageStatus('abgelehnt'), ['danger', 'Abgelehnt'])
assert.deepEqual(anfrageStatus('zurueckgezogen'), ['muted', 'Zurückgezogen'])
assert.deepEqual(anfrageStatus(undefined), ['muted', '–'])
})
const ANFRAGE = { warenart: 'kunst', beschreibung: ' Handgemachte Kerzen ', artikelzahl: 'bis20', versand: true, abholung: false, unternehmer: true, keineAusgeschlossenen: true, nachricht: '' }
test('anfrageZeilen: alle Angaben der Anfrage als Zeilen', () => {
assert.deepEqual(anfrageZeilen(ANFRAGE), [
{ label: 'Warenart', text: 'Kunst/Handgemachtes' },
{ label: 'Beschreibung', text: 'Handgemachte Kerzen' },
{ label: 'Artikelzahl', text: 'bis 20' },
{ label: 'Übergabe', text: 'Versand' },
{ label: 'Unternehmer', text: 'Ja' },
{ label: 'Keine ausgeschlossenen Waren', text: 'Ja' },
{ label: 'Nachricht', text: '–' },
])
assert.equal(anfrageZeilen({ ...ANFRAGE, abholung: true }).find((z) => z.label === 'Übergabe').text, 'Versand und Abholung')
assert.equal(anfrageZeilen({ ...ANFRAGE, versand: false }).find((z) => z.label === 'Übergabe').text, '–')
assert.deepEqual(anfrageZeilen(null), [])
})
test('anfrageText: eine Zeile aus Warenart, Menge und Übergabe', () => {
assert.equal(anfrageText(ANFRAGE), 'Kunst/Handgemachtes, bis 20 Artikel, Versand')
assert.equal(anfrageText({ ...ANFRAGE, abholung: true }), 'Kunst/Handgemachtes, bis 20 Artikel, Versand und Abholung')
assert.equal(anfrageText({ warenart: 'waren' }), 'Waren')
assert.equal(anfrageText(null), '')
})
test('stripeText: nicht verbunden, aktiv, Angaben fehlen', () => {
assert.equal(stripeText(null, false), 'nicht verbunden')
assert.equal(stripeText(undefined), 'nicht verbunden')
assert.equal(stripeText(null, true), 'Konto angelegt, Stand noch nicht geprüft')
assert.equal(stripeText({ charges_enabled: true, payouts_enabled: true }, true), 'Zahlungen aktiv')
assert.equal(stripeText({ charges_enabled: true, payouts_enabled: false }, true), 'Zahlungen aktiv, Auszahlungen noch nicht freigegeben')
assert.equal(stripeText({ charges_enabled: false, currently_due: ['external_account', 'individual.dob.day'], past_due: [] }, true), 'Angaben fehlen: external_account, individual.dob.day')
assert.equal(stripeText({ charges_enabled: false, past_due: ['a'], currently_due: ['a', 'b'] }, true), 'Angaben fehlen: a, b', 'doppelte Einträge nur einmal')
assert.equal(stripeText({ charges_enabled: false, currently_due: ['a', 'b', 'c', 'd', 'e', 'f'] }, true), 'Angaben fehlen: a, b, c, d und 2 weitere')
assert.equal(stripeText({ charges_enabled: false, currently_due: [], disabled_reason: 'requirements.pending_verification' }, true), 'Angaben fehlen: requirements.pending_verification')
assert.equal(stripeText({ charges_enabled: false, details_submitted: true }, true), 'Angaben fehlen: Prüfung durch Stripe läuft')
assert.equal(stripeText({ charges_enabled: false, details_submitted: false }, true), 'Angaben fehlen: Einrichtung nicht abgeschlossen')
})
test('stripeTon: ok, warn, muted', () => {
assert.equal(stripeTon({ charges_enabled: true }, true), 'ok')
assert.equal(stripeTon({ charges_enabled: false }, true), 'warn')
assert.equal(stripeTon(null, true), 'warn')
assert.equal(stripeTon(null, false), 'muted')
})
test('shopHatEintrag: Anfrage oder Zustand außer "off"', () => {
assert.equal(shopHatEintrag({ state: 'off', anfrage: null }), false)
assert.equal(shopHatEintrag({ state: 'off', anfrage: { status: 'offen' } }), true)
assert.equal(shopHatEintrag({ state: 'active', anfrage: null }), true)
assert.equal(shopHatEintrag({ state: 'disabled' }), true)
assert.equal(shopHatEintrag(null), false)
})
test('begruendungOk: Pflicht, höchstens 1000 Zeichen', () => {
assert.equal(begruendungOk(''), false)
assert.equal(begruendungOk(' '), false)
assert.equal(begruendungOk(undefined), false)
assert.equal(begruendungOk('Passt nicht'), true)
assert.equal(begruendungOk('x'.repeat(1000)), true)
assert.equal(begruendungOk('x'.repeat(1001)), false)
assert.equal(begruendungOk(` ${'x'.repeat(1000)} `), true, 'ohne Rand gezählt')
})
test('entscheidungBody: Begründung nur beim Ablehnen, getrimmt', () => {
assert.deepEqual(entscheidungBody({ projectId: 'p1', entscheidung: 'annehmen', begruendung: 'egal' }), { projectId: 'p1', entscheidung: 'annehmen' })
assert.deepEqual(entscheidungBody({ projectId: 'p1', entscheidung: 'ablehnen', begruendung: ' Zu groß ' }), { projectId: 'p1', entscheidung: 'ablehnen', begruendung: 'Zu groß' })
})
test('entscheidungStatus: Warnung, wenn die Mail an den Kunden fehlschlug', () => {
assert.deepEqual(entscheidungStatus({ ok: true }), { ok: true, text: 'Gespeichert.' })
assert.deepEqual(entscheidungStatus({ ok: true, mailFehler: true }), { ok: false, text: 'Entscheidung gespeichert, Mail an den Kunden fehlgeschlagen.' })
assert.deepEqual(entscheidungStatus(null), { ok: true, text: 'Gespeichert.' })
})