Auftragsbestaetigung: Listenlogik (Status, Aktionen, Meldungen, Fehlerklassen, Sperre) und PDF-Hilfe mit Tests
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
45dd73d8cc
commit
8b055a5d42
4 files changed
+585
No files matched your search
@@ -0,0 +1,51 @@
|
||||
import test from 'node:test'
|
||||
import assert from 'node:assert/strict'
|
||||
import { loadModule } from './load.mjs'
|
||||
|
||||
const { PDF_FREIGABE_NACH_MS, alsPdfBlob, oeffnePdfImTab } = await loadModule('src/lib/auftragPdf.js')
|
||||
|
||||
// Fester Ablauf: Tab zuerst (der Browser blockiert sonst das Pop-up), dann Blob holen, Objekt-URL erzeugen, später freigeben
|
||||
function umgebung() {
|
||||
const ablauf = []
|
||||
const tab = { location: {}, opener: 'woms', close: () => ablauf.push('schliessen') }
|
||||
const win = { open: (...args) => { ablauf.push('oeffnen'); win.args = args; return tab } }
|
||||
const urlApi = {
|
||||
createObjectURL: () => { ablauf.push('url'); return 'blob:https://woms.test/abc' },
|
||||
revokeObjectURL: (url) => ablauf.push(`frei:${url}`),
|
||||
}
|
||||
const timer = (fn, ms) => { ablauf.push(`timer:${ms}`); timer.fn = fn }
|
||||
return { ablauf, tab, win, urlApi, timer }
|
||||
}
|
||||
|
||||
test('alsPdfBlob: setzt den Typ application/pdf, ein passender Blob bleibt unverändert', async () => {
|
||||
const roh = new Blob(['%PDF-1.4'], { type: 'application/octet-stream' })
|
||||
const pdf = alsPdfBlob(roh)
|
||||
assert.equal(pdf.type, 'application/pdf')
|
||||
assert.equal(await pdf.text(), '%PDF-1.4')
|
||||
const schon = new Blob(['x'], { type: 'application/pdf' })
|
||||
assert.equal(alsPdfBlob(schon), schon)
|
||||
})
|
||||
|
||||
test('oeffnePdfImTab: Tab zuerst, dann Blob, Objekt-URL im Tab, später freigeben', async () => {
|
||||
const u = umgebung()
|
||||
await oeffnePdfImTab(async () => { u.ablauf.push('holen'); return new Blob(['%PDF'], { type: 'application/pdf' }) }, u)
|
||||
assert.equal(PDF_FREIGABE_NACH_MS, 300000)
|
||||
assert.deepEqual(u.ablauf, ['oeffnen', 'holen', 'url', 'timer:300000'])
|
||||
assert.equal(u.tab.location.href, 'blob:https://woms.test/abc')
|
||||
assert.equal(u.tab.opener, null)
|
||||
u.timer.fn()
|
||||
assert.equal(u.ablauf.at(-1), 'frei:blob:https://woms.test/abc')
|
||||
})
|
||||
|
||||
test('oeffnePdfImTab: Fehler beim Holen schließt den Tab, es entsteht keine URL', async () => {
|
||||
const u = umgebung()
|
||||
await assert.rejects(() => oeffnePdfImTab(async () => { u.ablauf.push('holen'); throw new Error('PDF nicht gefunden.') }, u), /PDF nicht gefunden/)
|
||||
assert.deepEqual(u.ablauf, ['oeffnen', 'holen', 'schliessen'])
|
||||
})
|
||||
|
||||
test('oeffnePdfImTab: blockiertes Pop-up, der Blob wird gar nicht geholt', async () => {
|
||||
let geholt = false
|
||||
const win = { open: () => null }
|
||||
await assert.rejects(() => oeffnePdfImTab(async () => { geholt = true; return new Blob() }, { win }), { message: 'Neuer Tab wurde vom Browser blockiert.' })
|
||||
assert.equal(geholt, false)
|
||||
})
|
||||
@@ -8,6 +8,8 @@ const {
|
||||
neuePosition, neuesFormular, auftragZuFormular, waehleProjekt, wechselArt, formularSummeCents,
|
||||
pruefeSchritt, formularZuNutzlast, zahlungsplanVorschau, sendeGate, zeitquelleOptionen, schalteZeitquelle,
|
||||
kundenartWirksam, VOR_ORT_HINWEIS, vorOrtHinweis, auftragHinweise,
|
||||
AUFTRAG_STATUS, PROJEKT_ZUORDNEN_STATUS, istEntwurf, zuordnenOptionen, projektZuordnenMoeglich, auftragAktionen,
|
||||
auftragNotizen, auftragZeilen, auftragBestaetigung, auftragErfolg, auftragFehler, neueSperre,
|
||||
} = await loadModule('src/lib/auftragView.js')
|
||||
|
||||
const KONTEN = [
|
||||
@@ -398,3 +400,281 @@ test('auftragHinweise: fehlende Steuernummer, dann „vor Ort“ bei Privatperso
|
||||
assert.deepEqual(hinweise(privatAmKunden).map((h) => h.key), ['vorOrt'])
|
||||
assert.deepEqual(hinweise({ ...privatAmKunden, einstellungen: { steuernummer: '' } }).map((h) => h.key), ['steuernummer', 'vorOrt'])
|
||||
})
|
||||
|
||||
// --- Liste -------------------------------------------------------------------------------------------------------------
|
||||
|
||||
const A = (o = {}) => ({
|
||||
id: 'a1', nummer: 'AB-2026-0002', status: 'versendet', kundenId: 'c1', projektId: 'p1', titel: 'Website Praxis Müller',
|
||||
art: 'festpreis', stundensatzCents: null, schaetzungMinuten: null, summeCents: 80000,
|
||||
gesendetAm: '2026-10-06T08:15:00.000+00:00', gesendetAn: 'info@praxis.test', mailStatus: 'gesendet', mailFehler: '',
|
||||
bestaetigtAm: null, bestaetigtUeber: '', fruehbeginn: false, ersetztId: '', ersetztDurchId: '', widerrufenAm: null,
|
||||
erstelltAm: '2026-10-05T16:00:00.000+00:00', geaendertAm: '2026-10-06T08:15:00.000+00:00',
|
||||
pdfVorhanden: true, fruehesterBeginn: null, zahlungsplanText: '', aufwandText: null, ...o,
|
||||
})
|
||||
|
||||
test('Status: Beschriftung und Ton für alle sieben Status (Vertrag V2)', () => {
|
||||
assert.deepEqual(Object.entries(AUFTRAG_STATUS).map(([k, v]) => [k, v.label]), [
|
||||
['entwurf', 'Entwurf'], ['versendet', 'Versendet'], ['bestaetigt', 'Bestätigt'], ['abgerechnet', 'Abgerechnet'],
|
||||
['storniert', 'Storniert'], ['ersetzt', 'Ersetzt'], ['widerrufen', 'Widerrufen'],
|
||||
])
|
||||
assert.deepEqual(Object.values(AUFTRAG_STATUS).map((v) => v.tone), ['muted', 'info', 'ok', 'violet', 'plain', 'plain', 'danger'])
|
||||
// „Projekt zuordnen“ gilt für diese Status (Übersicht, Nachträge; V5 `POST …/projekt` lehnt die übrigen mit 409 ab)
|
||||
assert.deepEqual(PROJEKT_ZUORDNEN_STATUS, ['entwurf', 'versendet', 'bestaetigt', 'abgerechnet'])
|
||||
})
|
||||
|
||||
test('auftragZeilen: Nummer, Titel, Datum, Summe und Status', () => {
|
||||
const [z] = auftragZeilen([A()])
|
||||
assert.deepEqual([z.id, z.nummerText, z.titel, z.datumText], ['a1', 'AB-2026-0002', 'Website Praxis Müller', '06.10.2026'])
|
||||
assert.deepEqual([z.summeText, z.summeSub, z.istEntwurf], ['800,00 €', '', false])
|
||||
assert.deepEqual([z.statusLabel, z.statusTone], ['Versendet', 'info'])
|
||||
assert.equal(z.auftrag.id, 'a1')
|
||||
})
|
||||
|
||||
test('auftragZeilen: Entwurf ohne Nummer, nach Aufwand, Projektname nur wenn er vom Titel abweicht', () => {
|
||||
const konten = [{ projektId: 'p1', name: 'Praxis Müller – Relaunch' }]
|
||||
const entwurf = A({
|
||||
id: 'a2', nummer: '', status: 'entwurf', gesendetAm: null, pdfVorhanden: false, art: 'aufwand', summeCents: null,
|
||||
stundensatzCents: 10000, schaetzungMinuten: 600, erstelltAm: '2026-10-05T22:30:00.000+00:00',
|
||||
})
|
||||
const [z] = auftragZeilen([entwurf], { konten })
|
||||
assert.deepEqual([z.nummerText, z.istEntwurf, z.datumText], ['Entwurf', true, '06.10.2026'])
|
||||
assert.deepEqual([z.summeText, z.summeSub], ['nach Aufwand', '100,00 € pro Std., Schätzung etwa 10 Std.'])
|
||||
assert.equal(z.projektText, 'Praxis Müller – Relaunch')
|
||||
assert.equal(auftragZeilen([A()], { konten: [{ projektId: 'p1', name: 'Website Praxis Müller' }] })[0].projektText, '')
|
||||
assert.equal(auftragZeilen([A({ projektId: '' })], { konten })[0].projektText, '')
|
||||
assert.equal(auftragZeilen([A({ projektId: 'p9' })], { konten })[0].projektText, '')
|
||||
assert.equal(auftragZeilen([A()])[0].projektText, '')
|
||||
assert.equal(auftragZeilen([A({ art: 'aufwand', summeCents: null, stundensatzCents: 9550, schaetzungMinuten: null })])[0].summeSub, '95,50 € pro Std.')
|
||||
assert.equal(auftragZeilen([A({ summeCents: null })])[0].summeText, '–')
|
||||
})
|
||||
|
||||
test('auftragZeilen: Notizen und Aktionen hängen an der Zeile, die Reihenfolge des Servers bleibt', () => {
|
||||
const zeilen = auftragZeilen([A({ id: 'x2', mailStatus: 'fehler' }), A({ id: 'x1', status: 'entwurf', nummer: '' })])
|
||||
assert.deepEqual(zeilen.map((z) => z.id), ['x2', 'x1'])
|
||||
assert.deepEqual(zeilen[0].notizen.map((n) => n.text), ['Mail nicht zugestellt'])
|
||||
assert.equal(zeilen[0].aktionen[1].label, 'Erneut senden')
|
||||
assert.equal(zeilen[1].istEntwurf, true)
|
||||
assert.deepEqual(auftragZeilen(null), [])
|
||||
assert.deepEqual(auftragZeilen([null, 'x', A()]).map((z) => z.id), ['a1'])
|
||||
})
|
||||
|
||||
test('Zusatzzeilen: Mail, bestätigt am, Frühbeginn, Arbeitsbeginn, Fassungen, Widerruf', () => {
|
||||
const texte = (o, alle) => auftragNotizen(A(o), alle).map((n) => n.text)
|
||||
const BESTAETIGT = '2026-10-07T09:00:00.000+00:00'
|
||||
assert.deepEqual(texte({}), [])
|
||||
assert.deepEqual(texte({ mailStatus: 'fehler', mailFehler: 'SMTP' }), ['Mail nicht zugestellt'])
|
||||
assert.deepEqual(auftragNotizen(A({ mailStatus: 'fehler' })).map((n) => n.tone), ['warn'])
|
||||
// nach der Bestätigung zählt ein früherer Mailfehler nicht mehr
|
||||
assert.deepEqual(texte({ status: 'bestaetigt', mailStatus: 'fehler', bestaetigtAm: BESTAETIGT }), ['Bestätigt am 07.10.2026'])
|
||||
assert.deepEqual(texte({ fruehesterBeginn: '2026-10-21' }), ['Arbeitsbeginn frühestens am 21.10.2026'])
|
||||
assert.deepEqual(texte({ status: 'bestaetigt', fruehbeginn: true, bestaetigtAm: BESTAETIGT }), ['Bestätigt am 07.10.2026', 'Frühbeginn verlangt'])
|
||||
assert.deepEqual(texte({ status: 'bestaetigt', fruehesterBeginn: '2026-10-21', bestaetigtAm: BESTAETIGT }), ['Bestätigt am 07.10.2026', 'Arbeitsbeginn frühestens am 21.10.2026'])
|
||||
// ohne Wirkung bei Entwurf und bei beendeten ABs
|
||||
assert.deepEqual(texte({ status: 'entwurf', fruehesterBeginn: '2026-10-21', fruehbeginn: true }), [])
|
||||
assert.deepEqual(texte({ status: 'storniert', fruehesterBeginn: '2026-10-21' }), [])
|
||||
assert.deepEqual(texte({ status: 'widerrufen', widerrufenAm: '2026-10-09T10:00:00.000+00:00' }), ['Widerrufen am 09.10.2026'])
|
||||
const alle = [
|
||||
A({ id: 'a1', nummer: 'AB-2026-0002', status: 'ersetzt', ersetztDurchId: 'a3' }),
|
||||
A({ id: 'a3', nummer: 'AB-2026-0004', ersetztId: 'a1' }),
|
||||
A({ id: 'a4', nummer: '', status: 'entwurf', ersetztId: 'a3' }),
|
||||
]
|
||||
assert.deepEqual(auftragNotizen(alle[0], alle).map((n) => n.text), ['Ersetzt durch AB-2026-0004'])
|
||||
assert.deepEqual(auftragNotizen(alle[1], alle).map((n) => n.text), ['Neue Fassung zu AB-2026-0002'])
|
||||
assert.deepEqual(auftragNotizen(alle[2], alle).map((n) => n.text), ['Neue Fassung zu AB-2026-0004'])
|
||||
assert.deepEqual(texte({ ersetztId: 'fremd' }, []), ['Neue Fassung'])
|
||||
assert.deepEqual(texte({ status: 'ersetzt', ersetztDurchId: 'fremd' }, []), ['Ersetzt durch eine neue Fassung'])
|
||||
})
|
||||
|
||||
test('auftragAktionen: je Status genau die erlaubten, nach dem Senden nur noch „Neue Fassung“ statt Bearbeiten', () => {
|
||||
const keys = (o) => auftragAktionen(A(o)).map((a) => a.key)
|
||||
assert.deepEqual(keys({ status: 'entwurf', pdfVorhanden: false }), ['bearbeiten', 'senden', 'pdf', 'loeschen'])
|
||||
assert.deepEqual(keys({ status: 'versendet' }), ['pdf', 'erinnern', 'neueFassung', 'stornieren'])
|
||||
assert.deepEqual(keys({ status: 'bestaetigt' }), ['pdf', 'neueFassung', 'stornieren'])
|
||||
assert.deepEqual(keys({ status: 'abgerechnet' }), ['pdf', 'neueFassung'])
|
||||
for (const status of ['storniert', 'ersetzt', 'widerrufen']) assert.deepEqual(keys({ status }), ['pdf'], status)
|
||||
for (const status of ['versendet', 'bestaetigt', 'abgerechnet', 'storniert', 'ersetzt', 'widerrufen']) {
|
||||
assert.equal(keys({ status }).some((k) => ['bearbeiten', 'senden', 'loeschen'].includes(k)), false, status)
|
||||
}
|
||||
// ohne gespeichertes PDF keine PDF-Aktion (beim Entwurf gibt es die Vorschau immer)
|
||||
assert.deepEqual(keys({ status: 'versendet', pdfVorhanden: false }), ['erinnern', 'neueFassung', 'stornieren'])
|
||||
assert.deepEqual(keys({ status: 'storniert', pdfVorhanden: false }), [])
|
||||
assert.deepEqual(auftragAktionen(A({ status: 'entwurf' })).map((a) => a.label), ['Bearbeiten', 'Senden', 'Vorschau', 'Löschen'])
|
||||
assert.deepEqual(auftragAktionen(A()).map((a) => a.label), ['PDF', 'Erinnerung senden', 'Neue Fassung', 'Stornieren'])
|
||||
assert.equal(auftragAktionen(A({ mailStatus: 'fehler' }))[1].label, 'Erneut senden')
|
||||
assert.deepEqual(auftragAktionen(A({ status: 'entwurf' })).filter((a) => a.danger).map((a) => a.key), ['loeschen'])
|
||||
assert.deepEqual(auftragAktionen(A()).filter((a) => a.danger).map((a) => a.key), ['stornieren'])
|
||||
assert.deepEqual(auftragAktionen(A({ status: 'xyz', pdfVorhanden: false })), [])
|
||||
assert.deepEqual(auftragAktionen(null), [])
|
||||
assert.equal(istEntwurf(A({ status: 'entwurf' })), true)
|
||||
assert.equal(istEntwurf(A()), false)
|
||||
assert.equal(istEntwurf(null), false)
|
||||
})
|
||||
|
||||
test('Projekt zuordnen: Auswahl aus den Konten, Verfügbarkeit nach Status und Projekt', () => {
|
||||
const konten = [{ projektId: 'p1', name: 'Website Praxis Müller' }, { projektId: 'p2', name: ' Shop Relaunch ' }, { projektId: 'p3', name: '' }, { name: 'ohne Kennung' }, null]
|
||||
assert.deepEqual(zuordnenOptionen(konten), [
|
||||
{ value: 'p1', label: 'Website Praxis Müller' }, { value: 'p2', label: 'Shop Relaunch' }, { value: 'p3', label: 'p3' },
|
||||
])
|
||||
assert.deepEqual(zuordnenOptionen(undefined), [])
|
||||
assert.deepEqual(zuordnenOptionen('x'), [])
|
||||
const ohne = (o) => A({ projektId: '', ...o })
|
||||
for (const status of ['entwurf', 'versendet', 'bestaetigt', 'abgerechnet']) {
|
||||
assert.equal(projektZuordnenMoeglich(ohne({ status }), konten), true, status)
|
||||
}
|
||||
for (const status of ['storniert', 'ersetzt', 'widerrufen', 'xyz']) {
|
||||
assert.equal(projektZuordnenMoeglich(ohne({ status }), konten), false, status)
|
||||
}
|
||||
assert.equal(projektZuordnenMoeglich(ohne({ projektId: null }), konten), true)
|
||||
assert.equal(projektZuordnenMoeglich(ohne({ projektId: undefined }), konten), true)
|
||||
// hat die AB schon ein Projekt (auch ein unbekanntes), gibt es die Aktion nicht: der Server lehnt sie mit 409 ab
|
||||
assert.equal(projektZuordnenMoeglich(A({ projektId: 'p1' }), konten), false)
|
||||
assert.equal(projektZuordnenMoeglich(A({ projektId: 'p9' }), konten), false)
|
||||
// ohne Projekt zur Auswahl ist nichts zu tun
|
||||
assert.equal(projektZuordnenMoeglich(ohne({}), []), false)
|
||||
assert.equal(projektZuordnenMoeglich(ohne({}), undefined), false)
|
||||
assert.equal(projektZuordnenMoeglich(null, konten), false)
|
||||
})
|
||||
|
||||
test('auftragAktionen mit Konten: „Projekt zuordnen“ nur ohne Projekt, vor den gefährlichen Aktionen', () => {
|
||||
const konten = [{ projektId: 'p1', name: 'Website' }]
|
||||
const keys = (o, k = konten) => auftragAktionen(A({ projektId: '', ...o }), { konten: k }).map((a) => a.key)
|
||||
assert.deepEqual(keys({ status: 'entwurf', pdfVorhanden: false }), ['bearbeiten', 'senden', 'pdf', 'projekt', 'loeschen'])
|
||||
assert.deepEqual(keys({ status: 'versendet' }), ['pdf', 'erinnern', 'neueFassung', 'projekt', 'stornieren'])
|
||||
assert.deepEqual(keys({ status: 'bestaetigt' }), ['pdf', 'neueFassung', 'projekt', 'stornieren'])
|
||||
assert.deepEqual(keys({ status: 'abgerechnet' }), ['pdf', 'neueFassung', 'projekt'])
|
||||
assert.deepEqual(keys({ status: 'versendet', pdfVorhanden: false }), ['erinnern', 'neueFassung', 'projekt', 'stornieren'])
|
||||
for (const status of ['storniert', 'ersetzt', 'widerrufen']) assert.deepEqual(keys({ status }), ['pdf'], status)
|
||||
// mit Projekt, ohne Konten und ohne Angabe der Konten gibt es die Aktion nicht
|
||||
assert.deepEqual(auftragAktionen(A({ status: 'versendet' }), { konten }).map((a) => a.key), ['pdf', 'erinnern', 'neueFassung', 'stornieren'])
|
||||
assert.deepEqual(keys({ status: 'versendet' }, []), ['pdf', 'erinnern', 'neueFassung', 'stornieren'])
|
||||
assert.deepEqual(auftragAktionen(A({ projektId: '' })).map((a) => a.key), ['pdf', 'erinnern', 'neueFassung', 'stornieren'])
|
||||
// Beschriftung, nie gefährlich; Bearbeiten, Senden und Löschen bleiben dem Entwurf vorbehalten
|
||||
const aktion = auftragAktionen(A({ projektId: '' }), { konten }).find((a) => a.key === 'projekt')
|
||||
assert.equal(aktion.label, 'Projekt zuordnen')
|
||||
assert.notEqual(aktion.danger, true)
|
||||
assert.equal(keys({ status: 'versendet' }).some((k) => ['bearbeiten', 'senden', 'loeschen'].includes(k)), false)
|
||||
// die Zeilen geben die Konten weiter
|
||||
assert.deepEqual(auftragZeilen([A({ projektId: '' })], { konten })[0].aktionen.map((a) => a.key), ['pdf', 'erinnern', 'neueFassung', 'projekt', 'stornieren'])
|
||||
assert.deepEqual(auftragZeilen([A({ projektId: '' })])[0].aktionen.map((a) => a.key), ['pdf', 'erinnern', 'neueFassung', 'stornieren'])
|
||||
})
|
||||
|
||||
test('Rückfragen: Senden, Löschen, Stornieren, Erinnerung, Projekt zuordnen', () => {
|
||||
assert.equal(
|
||||
auftragBestaetigung('senden', A({ status: 'entwurf', nummer: '' }), { email: 'info@praxis.test' }),
|
||||
'Auftragsbestätigung „Website Praxis Müller“ jetzt festschreiben und an info@praxis.test senden? Danach lässt sie sich nicht mehr ändern, nur noch ersetzen oder stornieren.'
|
||||
)
|
||||
assert.equal(
|
||||
auftragBestaetigung('senden', A({ status: 'entwurf', nummer: '' })),
|
||||
'Auftragsbestätigung „Website Praxis Müller“ jetzt festschreiben und an den Kunden senden? Danach lässt sie sich nicht mehr ändern, nur noch ersetzen oder stornieren.'
|
||||
)
|
||||
assert.equal(auftragBestaetigung('loeschen', A({ status: 'entwurf' })), 'Den Entwurf „Website Praxis Müller“ wirklich löschen? Das lässt sich nicht rückgängig machen.')
|
||||
assert.equal(
|
||||
auftragBestaetigung('stornieren', A()),
|
||||
'Die Auftragsbestätigung AB-2026-0002 „Website Praxis Müller“ wirklich stornieren? Der Kunde bekommt keine Mail, der Bestätigungslink wird ungültig. Das lässt sich nicht rückgängig machen.'
|
||||
)
|
||||
assert.equal(
|
||||
auftragBestaetigung('erinnern', A()),
|
||||
'Die Auftragsbestätigung AB-2026-0002 jetzt noch einmal an den Kunden senden? Der bisherige Bestätigungslink gilt danach nicht mehr.'
|
||||
)
|
||||
assert.equal(
|
||||
auftragBestaetigung('projekt', A({ projektId: '' }), { projektName: 'Physio-Website' }),
|
||||
'Die Auftragsbestätigung AB-2026-0002 „Website Praxis Müller“ dem Projekt „Physio-Website“ zuordnen? Das Projekt lässt sich danach nur noch über eine neue Fassung ändern.'
|
||||
)
|
||||
assert.match(auftragBestaetigung('projekt', A({ projektId: '' })), /„Website Praxis Müller“ einem Projekt zuordnen\? /)
|
||||
// ein Entwurf bleibt über „Bearbeiten“ änderbar: keine Rückfrage
|
||||
assert.equal(auftragBestaetigung('projekt', A({ status: 'entwurf', nummer: '', projektId: '' }), { projektName: 'Physio-Website' }), '')
|
||||
for (const key of ['bearbeiten', 'pdf', 'neueFassung', 'gibtsnicht']) assert.equal(auftragBestaetigung(key, A()), '', key)
|
||||
assert.match(auftragBestaetigung('senden', A({ titel: '' })), /„ohne Titel“/)
|
||||
})
|
||||
|
||||
test('Erfolgsmeldungen (Wortlaut des Containers von W0 für „senden“)', () => {
|
||||
const gesendet = A({ nummer: 'AB-2026-0003' }) // gesendetAn: info@praxis.test
|
||||
assert.deepEqual(auftragErfolg('senden', gesendet), { tone: 'ok', text: 'Auftragsbestätigung AB-2026-0003 wurde an info@praxis.test gesendet.' })
|
||||
assert.deepEqual(auftragErfolg('senden', A({ nummer: 'AB-2026-0003', gesendetAn: '' })), { tone: 'ok', text: 'Auftragsbestätigung AB-2026-0003 wurde gesendet.' })
|
||||
assert.deepEqual(auftragErfolg('senden', gesendet, { mailFehler: true }), {
|
||||
tone: 'warn',
|
||||
text: 'Auftragsbestätigung AB-2026-0003 ist versendet, die Mail an den Kunden wurde aber nicht zugestellt. Bitte in der Liste erneut senden.',
|
||||
})
|
||||
assert.deepEqual(auftragErfolg('erinnern', gesendet), { tone: 'ok', text: 'Die Erinnerung zu AB-2026-0003 wurde an info@praxis.test gesendet.' })
|
||||
assert.deepEqual(auftragErfolg('erinnern', gesendet, { mailFehler: true }), {
|
||||
tone: 'warn', text: 'Die Erinnerung zu AB-2026-0003 konnte nicht zugestellt werden. „Erneut senden“ versucht es noch einmal.',
|
||||
})
|
||||
assert.deepEqual(auftragErfolg('stornieren', gesendet), { tone: 'ok', text: 'Auftragsbestätigung AB-2026-0003 wurde storniert.' })
|
||||
assert.deepEqual(auftragErfolg('loeschen', A({ nummer: '' })), { tone: 'ok', text: 'Der Entwurf wurde gelöscht.' })
|
||||
assert.deepEqual(auftragErfolg('neueFassung', A({ nummer: '' })), { tone: 'ok', text: 'Neue Fassung als Entwurf angelegt.' })
|
||||
assert.deepEqual(auftragErfolg('projekt', gesendet, { projektName: 'Physio-Website' }), {
|
||||
tone: 'ok', text: 'Auftragsbestätigung AB-2026-0003 wurde dem Projekt „Physio-Website“ zugeordnet.',
|
||||
})
|
||||
assert.deepEqual(auftragErfolg('projekt', gesendet), { tone: 'ok', text: 'Auftragsbestätigung AB-2026-0003 wurde einem Projekt zugeordnet.' })
|
||||
assert.deepEqual(auftragErfolg('projekt', A({ nummer: '' }), { projektName: 'Physio-Website' }), {
|
||||
tone: 'ok', text: 'Die Auftragsbestätigung wurde dem Projekt „Physio-Website“ zugeordnet.',
|
||||
})
|
||||
assert.deepEqual(auftragErfolg('senden', null), { tone: 'ok', text: 'Die Auftragsbestätigung wurde gesendet.' })
|
||||
assert.deepEqual(auftragErfolg('senden', null, { mailFehler: true }), {
|
||||
tone: 'warn', text: 'Die Auftragsbestätigung ist versendet, die Mail an den Kunden wurde aber nicht zugestellt. Bitte in der Liste erneut senden.',
|
||||
})
|
||||
assert.deepEqual(auftragErfolg('gibtsnicht', gesendet), { tone: 'ok', text: '' })
|
||||
})
|
||||
|
||||
test('auftragFehler: Kundendaten-Fehler führen zur Übersicht, andere zeigen die Meldung des Servers (Texte aus Plan L3)', () => {
|
||||
const fehler = (status, message) => auftragFehler(Object.assign(new Error(message), { status }))
|
||||
assert.deepEqual(fehler(409, 'Adresse des Kunden unvollständig (Straße, PLZ, Ort). Für den Versand bitte zuerst ergänzen.'), {
|
||||
art: 'adresse', text: 'Adresse des Kunden unvollständig (Straße, PLZ, Ort). Für den Versand bitte zuerst ergänzen.', zurUebersicht: true,
|
||||
})
|
||||
assert.deepEqual(fehler(400, 'Bitte zuerst die Kundenart angeben (Unternehmen oder Privatperson).'), {
|
||||
art: 'kundenart',
|
||||
text: 'Die Kundenart des Kunden fehlt. Bitte in der Übersicht des Kunden festlegen (Feld „Kundenart“) oder über „Bearbeiten“ und dann erneut senden.',
|
||||
zurUebersicht: true,
|
||||
})
|
||||
assert.deepEqual(fehler(400, 'Für den Versand fehlt die E-Mail-Adresse des Kunden.'), {
|
||||
art: 'email', text: 'Dem Kunden fehlt die E-Mail-Adresse. Bitte in der Übersicht eintragen und dann erneut senden.', zurUebersicht: true,
|
||||
})
|
||||
assert.deepEqual(fehler(400, 'Auftragsbestätigungen nur für feste Kunden.'), {
|
||||
art: 'kunde', text: 'Das ist noch kein fester Kunde. Bitte in der Übersicht zum festen Kunden machen und dann erneut senden.', zurUebersicht: true,
|
||||
})
|
||||
// Entwurf unvollständig (L4, wird von L3 beim Senden und bei der Vorschau durchgereicht): Meldung unverändert, kein „aktueller Stand“
|
||||
assert.deepEqual(fehler(409, 'Entwurf unvollständig: Titel fehlt.'), {
|
||||
art: 'entwurf', text: 'Entwurf unvollständig: Titel fehlt.', zurUebersicht: false,
|
||||
})
|
||||
assert.equal(fehler(409, 'Entwurf unvollständig: Kundendaten fehlen.').art, 'entwurf')
|
||||
assert.deepEqual(fehler(409, 'Nur ein Entwurf lässt sich senden.'), {
|
||||
art: 'stand', text: 'Nur ein Entwurf lässt sich senden. Die Liste zeigt den aktuellen Stand.', zurUebersicht: false,
|
||||
})
|
||||
assert.deepEqual(fehler(400, 'Titel: Bitte einen Titel angeben oder ein Projekt wählen.'), {
|
||||
art: 'eingabe', text: 'Titel: Bitte einen Titel angeben oder ein Projekt wählen.', zurUebersicht: false,
|
||||
})
|
||||
assert.deepEqual(fehler(500, 'Das PDF konnte nicht erzeugt werden.'), {
|
||||
art: 'pdf', text: 'Das PDF konnte nicht erzeugt werden. Die Auftragsbestätigung bleibt ein Entwurf, es wurde keine Nummer vergeben.', zurUebersicht: false,
|
||||
})
|
||||
assert.deepEqual(fehler(500, 'Interner Fehler.'), {
|
||||
art: 'server',
|
||||
text: 'Interner Fehler. Bitte in der Liste prüfen, ob die Auftragsbestätigung gesendet wurde, und sonst erneut versuchen.',
|
||||
zurUebersicht: false,
|
||||
})
|
||||
assert.deepEqual(fehler(0, 'Das Kundenportal ist gerade nicht erreichbar.'), { art: 'netz', text: 'Das Kundenportal ist gerade nicht erreichbar.', zurUebersicht: false })
|
||||
assert.deepEqual(fehler(404, 'Auftragsbestätigung nicht gefunden.'), { art: 'sonst', text: 'Auftragsbestätigung nicht gefunden.', zurUebersicht: false })
|
||||
assert.deepEqual(auftragFehler(new Error('')), { art: 'sonst', text: 'Die Aktion ist fehlgeschlagen.', zurUebersicht: false })
|
||||
assert.deepEqual(auftragFehler(null), { art: 'sonst', text: 'Die Aktion ist fehlgeschlagen.', zurUebersicht: false })
|
||||
})
|
||||
|
||||
test('neueSperre: ein zweiter Aufruf während des ersten wird ignoriert (Doppelklick)', async () => {
|
||||
const sperre = neueSperre()
|
||||
let aufrufe = 0
|
||||
let fertig
|
||||
const warten = new Promise((r) => { fertig = r })
|
||||
const erster = sperre.run(async () => { aufrufe += 1; await warten; return 'ok' })
|
||||
const zweiter = await sperre.run(async () => { aufrufe += 1; return 'doppelt' })
|
||||
assert.deepEqual(zweiter, { uebersprungen: true })
|
||||
assert.equal(sperre.belegt, true)
|
||||
fertig()
|
||||
assert.deepEqual(await erster, { uebersprungen: false, wert: 'ok' })
|
||||
assert.equal(aufrufe, 1)
|
||||
assert.equal(sperre.belegt, false)
|
||||
assert.deepEqual(await sperre.run(async () => 'wieder'), { uebersprungen: false, wert: 'wieder' })
|
||||
})
|
||||
|
||||
test('neueSperre: nach einem Fehler wieder frei, der Fehler wird weitergereicht', async () => {
|
||||
const sperre = neueSperre()
|
||||
await assert.rejects(() => sperre.run(async () => { throw new Error('kaputt') }), /kaputt/)
|
||||
assert.equal(sperre.belegt, false)
|
||||
})
|
||||
Reference in new issue
Block a user