diff --git a/src/lib/auftraegeAnsicht.js b/src/lib/auftraegeAnsicht.js index 8732565..16258dc 100644 --- a/src/lib/auftraegeAnsicht.js +++ b/src/lib/auftraegeAnsicht.js @@ -1,6 +1,7 @@ // Ansichtslogik des Reiters „Aufträge und Rechnungen“ (rein, ohne React und ohne Appwrite; unter Node testbar). // Die API-Funktionen kommen als Argument. Der Container (AuftraegeUndRechnungen.jsx) verdrahtet diese Funktionen mit // useFinanceResource und den Abschnitten des Reiters. +import { invoiceDoneMessage } from './financeView' export const KONTEN_FEHLER = 'Die Projektübersicht konnte nicht geladen werden.' export const AUFTRAEGE_FEHLER = 'Die Aufträge konnten nicht geladen werden.' @@ -67,3 +68,40 @@ export function ansichtsZustand({ data, error } = {}) { auftraege: auftraegeAktiv && Array.isArray(data.auftraege) ? data.auftraege : [], } } + +// Wertebereich von customers.kundenart (V1); bewusst lokal, auftragView.js gehört dem Strang W2 +const KUNDENARTEN = ['unternehmen', 'privat'] + +/** + * Kundendokument mit der frischen Kundenart des Portals (getProjektkonten -> kunde.kundenart). Gilt nur ein gültiger Wert + * („unternehmen“ oder „privat“), kommt eine Kopie mit diesem Wert zurück, das Dokument der Seite bleibt unverändert. + * Sonst dieselbe Referenz (null bleibt null). So fragt der AB-Dialog nicht erneut, wenn die Kundenart eben gespeichert wurde + * und die Kundenseite noch den alten Datensatz hält. + */ +export function kundeMitKundenart(customer, kundeInfo) { + const art = istObjekt(kundeInfo) ? kundeInfo.kundenart : undefined + if (!customer || !KUNDENARTEN.includes(art)) return customer + return { ...customer, kundenart: art } +} + +/** + * Rückmeldung nach dem Anlegen einer Rechnung (wie InvoiceTable.handleCreated): `info.notice` (festgeschrieben, aber nicht + * versendet) gewinnt mit seinem Ton, sonst Entwurf oder gesendet. `info` darf fehlen oder null sein. -> { tone, text } + */ +export function erstelltMeldung(rechnung, info) { + const i = istObjekt(info) ? info : {} + if (typeof i.notice === 'string' && i.notice) return { tone: i.tone || 'ok', text: i.notice } + return { tone: 'ok', text: invoiceDoneMessage(i.senden ? 'create-send' : 'create-draft', rechnung) } +} + +/** Rückmeldung nach dem Speichern oder Senden einer Auftragsbestätigung (onSaved des AB-Dialogs). -> { tone, text } */ +export function auftragMeldung(auftrag) { + const a = istObjekt(auftrag) ? auftrag : {} + const name = a.nummer ? `Auftragsbestätigung ${a.nummer}` : 'Die Auftragsbestätigung' + if (a.status === 'entwurf') return { tone: 'ok', text: 'Der Entwurf wurde gespeichert.' } + if (a.mailStatus === 'fehler') { + return { tone: 'warn', text: `${name} ist versendet, die Mail an den Kunden wurde aber nicht zugestellt. Bitte in der Liste erneut senden.` } + } + if (a.nummer) return { tone: 'ok', text: `${name} wurde${a.gesendetAn ? ` an ${a.gesendetAn}` : ''} gesendet.` } + return { tone: 'ok', text: 'Die Auftragsbestätigung wurde gespeichert.' } +} diff --git a/tests/unit/auftraegeAnsicht.test.mjs b/tests/unit/auftraegeAnsicht.test.mjs index 857036c..3f744ff 100644 --- a/tests/unit/auftraegeAnsicht.test.mjs +++ b/tests/unit/auftraegeAnsicht.test.mjs @@ -2,7 +2,9 @@ import test from 'node:test' import assert from 'node:assert/strict' import { loadModule } from './load.mjs' -const { KONTEN_FEHLER, AUFTRAEGE_FEHLER, ladeAuftraegeAnsicht, ansichtsZustand } = await loadModule('src/lib/auftraegeAnsicht.js') +const { + KONTEN_FEHLER, AUFTRAEGE_FEHLER, ladeAuftraegeAnsicht, ansichtsZustand, kundeMitKundenart, erstelltMeldung, auftragMeldung, +} = await loadModule('src/lib/auftraegeAnsicht.js') // Antwort von getProjektkonten (V5) mit den Feldern, die die Ansicht braucht const konten = (extra = {}) => ({ @@ -142,3 +144,44 @@ test('ansichtsZustand: unvollständige Antworten brechen die Ansicht nicht', () } assert.equal(ansichtsZustand({ data: { konten: konten({ stripeOk: false }) }, error: '' }).stripeOk, false) }) + +test('kundeMitKundenart: ein gültiger Wert des Portals gewinnt gegen das veraltete Kundendokument', () => { + const doc = { $id: 'k1', name: 'Anelia Wolf', kundenart: '' } + assert.deepEqual(kundeMitKundenart(doc, { id: 'k1', kundenart: 'privat' }), { ...doc, kundenart: 'privat' }) + assert.equal(doc.kundenart, '') // das Dokument der Seite wird nicht verändert + assert.equal(kundeMitKundenart({ ...doc, kundenart: 'unternehmen' }, { kundenart: 'privat' }).kundenart, 'privat') +}) + +test('kundeMitKundenart: ohne gültigen Wert vom Portal bleibt das Dokument (dieselbe Referenz)', () => { + const doc = { $id: 'k1', kundenart: 'unternehmen' } + for (const info of [null, undefined, {}, { kundenart: '' }, { kundenart: 'firma' }, { kundenart: 5 }, 'privat']) { + assert.equal(kundeMitKundenart(doc, info), doc) + } + assert.equal(kundeMitKundenart(null, { kundenart: 'privat' }), null) +}) + +test('erstelltMeldung: gesendet, Entwurf und die Meldung nach festgeschriebener, nicht gesendeter Rechnung', () => { + assert.deepEqual( + erstelltMeldung({ number: 'WEBKLAR-0009', customerEmail: 'a@b.de' }, { senden: true }), + { tone: 'ok', text: 'Rechnung WEBKLAR-0009 wurde an a@b.de gesendet.' }, + ) + assert.deepEqual(erstelltMeldung({ id: 'in_1' }, { senden: false }), { tone: 'ok', text: 'Der Entwurf wurde gespeichert.' }) + assert.deepEqual(erstelltMeldung(null, undefined), { tone: 'ok', text: 'Der Entwurf wurde gespeichert.' }) + assert.deepEqual(erstelltMeldung(null, null), { tone: 'ok', text: 'Der Entwurf wurde gespeichert.' }) + const text = 'Rechnung WEBKLAR-0010 wurde festgeschrieben, aber nicht versendet. Bitte in der Liste erneut senden.' + assert.deepEqual(erstelltMeldung(null, { senden: true, notice: text, tone: 'warn', finalizedFilter: 'offen' }), { tone: 'warn', text }) + assert.deepEqual(erstelltMeldung(null, { senden: true, notice: text }), { tone: 'ok', text }) +}) + +test('auftragMeldung: Entwurf, gesendet und gesendet ohne zugestellte Mail', () => { + assert.deepEqual(auftragMeldung({ status: 'entwurf', nummer: '' }), { tone: 'ok', text: 'Der Entwurf wurde gespeichert.' }) + assert.deepEqual( + auftragMeldung({ status: 'versendet', nummer: 'AB-2026-0001', gesendetAn: 'k@x.de', mailStatus: 'gesendet' }), + { tone: 'ok', text: 'Auftragsbestätigung AB-2026-0001 wurde an k@x.de gesendet.' }, + ) + assert.deepEqual( + auftragMeldung({ status: 'versendet', nummer: 'AB-2026-0001', gesendetAn: 'k@x.de', mailStatus: 'fehler' }), + { tone: 'warn', text: 'Auftragsbestätigung AB-2026-0001 ist versendet, die Mail an den Kunden wurde aber nicht zugestellt. Bitte in der Liste erneut senden.' }, + ) + assert.deepEqual(auftragMeldung(null), { tone: 'ok', text: 'Die Auftragsbestätigung wurde gespeichert.' }) +})