diff --git a/src/lib/auftraegeAnsicht.js b/src/lib/auftraegeAnsicht.js index 16258dc..a643356 100644 --- a/src/lib/auftraegeAnsicht.js +++ b/src/lib/auftraegeAnsicht.js @@ -11,12 +11,30 @@ const ohneProjektLeer = () => ({ berechnetCents: 0, bezahltCents: 0, anzahl: 0 } /** * Lädt Projektkonten und, nur bei eingeschaltetem Schalter (`auftraegeAktiv === true`), die Aufträge des Kunden. - * Scheitert getProjektkonten, geht der Fehler weiter (keine Aufträge, sie würden ohne Schalter 404 liefern). * Scheitert nur listAuftraege, bleiben die Projektkonten und der Fehler steht eigens da. - * -> { konten, auftraege: Liste | null, auftraegeFehler: Text | '' } + * Scheitert getProjektkonten, wird die Auftragsliste trotzdem geholt (der Server prüft den Schalter ohnehin und antwortet bei + * „aus“ mit 404): kommt sie, bleibt der Abschnitt Aufträge bedienbar und der Fehler steht als `kontenFehler` daneben; + * kommt sie nicht, geht der Fehler der Projektkonten weiter. + * -> { konten, auftraege: Liste | null, auftraegeFehler: Text | '', kontenFehler?: Text (nur bei ausgefallenen Projektkonten) } */ export async function ladeAuftraegeAnsicht(kundeId, { getProjektkonten, listAuftraege }) { - const antwort = await getProjektkonten(kundeId) + let antwort + try { + antwort = await getProjektkonten(kundeId) + } catch (kontenErr) { + let liste + try { + liste = await listAuftraege(kundeId) + } catch { + throw kontenErr + } + return { + konten: {}, + kontenFehler: (kontenErr && kontenErr.message) || KONTEN_FEHLER, + auftraege: Array.isArray(liste?.auftraege) ? liste.auftraege : [], + auftraegeFehler: '', + } + } const konten = istObjekt(antwort) ? antwort : {} if (konten.auftraegeAktiv !== true) return { konten, auftraege: null, auftraegeFehler: '' } try { @@ -33,7 +51,8 @@ export async function ladeAuftraegeAnsicht(kundeId, { getProjektkonten, listAuft * auftraegeAktiv, auftraegeStatus: 'aus' | 'bereit' | 'fehler', auftraegeFehler, * konten, ohneProjekt, stripeOk, kunde, auftraege } * Ohne Daten gibt es keinen Aufträge-Abschnitt (der Schalter ist noch unbekannt). Scheitert das Neuladen, nachdem Daten - * da sind, bleiben die alten Daten stehen und die Meldung kommt als `nachladeFehler` daneben. + * da sind, bleiben die alten Daten stehen und die Meldung kommt als `nachladeFehler` daneben. Waren die Projektkonten + * ausgefallen und die Aufträge trotzdem da (`data.kontenFehler`), ist `projekteStatus` „fehler“ und die Aufträge sind bereit. */ export function ansichtsZustand({ data, error } = {}) { if (!data) { @@ -52,12 +71,14 @@ export function ansichtsZustand({ data, error } = {}) { } } const k = istObjekt(data.konten) ? data.konten : {} - const auftraegeAktiv = k.auftraegeAktiv === true + const kontenFehler = typeof data.kontenFehler === 'string' ? data.kontenFehler : '' + // Mit ausgefallenen Projektkonten gilt der Schalter als an, wenn der Server die Auftragsliste geliefert hat + const auftraegeAktiv = kontenFehler ? Array.isArray(data.auftraege) : k.auftraegeAktiv === true const auftraegeStatus = !auftraegeAktiv ? 'aus' : data.auftraegeFehler ? 'fehler' : 'bereit' return { - projekteStatus: 'bereit', - fehler: '', - nachladeFehler: error || '', + projekteStatus: kontenFehler ? 'fehler' : 'bereit', + fehler: kontenFehler ? error || kontenFehler : '', + nachladeFehler: kontenFehler ? '' : error || '', auftraegeAktiv, auftraegeStatus, auftraegeFehler: auftraegeStatus === 'fehler' ? data.auftraegeFehler : '', diff --git a/tests/unit/auftraegeAnsicht.test.mjs b/tests/unit/auftraegeAnsicht.test.mjs index 3f744ff..3844096 100644 --- a/tests/unit/auftraegeAnsicht.test.mjs +++ b/tests/unit/auftraegeAnsicht.test.mjs @@ -72,11 +72,39 @@ test('Aufträge scheitern allein: die Projektkonten bleiben, der Fehler steht ei assert.equal(AUFTRAEGE_FEHLER, 'Die Aufträge konnten nicht geladen werden.') }) -test('Projektkonten scheitern: der Fehler geht weiter, die Aufträge werden nicht abgerufen', async () => { +test('Projektkonten scheitern, Aufträge laden: der Abschnitt Aufträge bleibt bedienbar, der Konten-Fehler steht eigens da', async () => { const fehler = Object.assign(new Error('Interner Fehler.'), { status: 500 }) - const api = fakeApi({ projektkonten: fehler, auftraege: { auftraege: [] } }) + const liste = [{ id: 'a1', nummer: 'AB-2026-0001', status: 'versendet' }] + const api = fakeApi({ projektkonten: fehler, auftraege: { auftraege: liste } }) + const result = await ladeAuftraegeAnsicht('k1', api) + assert.deepEqual(api.calls, [['konten', 'k1'], ['auftraege', 'k1']]) + assert.deepEqual(result, { konten: {}, kontenFehler: 'Interner Fehler.', auftraege: liste, auftraegeFehler: '' }) + const ohneText = await ladeAuftraegeAnsicht('k1', fakeApi({ projektkonten: new Error(''), auftraege: { auftraege: liste } })) + assert.equal(ohneText.kontenFehler, KONTEN_FEHLER) +}) + +test('Projektkonten und Aufträge scheitern: der Fehler der Projektkonten geht weiter (Schalter aus gibt 404)', async () => { + const fehler = Object.assign(new Error('Interner Fehler.'), { status: 500 }) + const api = fakeApi({ projektkonten: fehler, auftraege: Object.assign(new Error('Nicht gefunden.'), { status: 404 }) }) await assert.rejects(ladeAuftraegeAnsicht('k1', api), (e) => e === fehler) - assert.deepEqual(api.calls, [['konten', 'k1']]) + assert.deepEqual(api.calls, [['konten', 'k1'], ['auftraege', 'k1']]) +}) + +test('ansichtsZustand: Projekte-Fehler mit geladenen Aufträgen – Projekte „fehler“, Aufträge „bereit“', () => { + const liste = [{ id: 'a1' }] + const z = ansichtsZustand({ data: { konten: {}, kontenFehler: 'Interner Fehler.', auftraege: liste, auftraegeFehler: '' }, error: '' }) + assert.equal(z.projekteStatus, 'fehler') + assert.equal(z.fehler, 'Interner Fehler.') + assert.equal(z.auftraegeAktiv, true) // der Server hat die Liste geliefert, der Schalter ist also an + assert.equal(z.auftraegeStatus, 'bereit') + assert.deepEqual(z.auftraege, liste) + assert.deepEqual(z.konten, []) + assert.equal(z.nachladeFehler, '') + // scheitert auch ein späteres Neuladen, steht dessen Meldung im Fehlerkasten; die Aufträge bleiben stehen + const spaeter = ansichtsZustand({ data: { konten: {}, kontenFehler: 'Interner Fehler.', auftraege: liste, auftraegeFehler: '' }, error: 'Netz weg' }) + assert.equal(spaeter.projekteStatus, 'fehler') + assert.equal(spaeter.fehler, 'Netz weg') + assert.equal(spaeter.auftraegeStatus, 'bereit') }) test('ansichtsZustand: vor der ersten Antwort „laden“, nach einem Fehler „fehler“ mit der Meldung', () => {