Files
Webklar-Kundenbereich/test/auftraegeEntwurf.test.js
T
2026-10-07 14:13:26 +00:00

120 lines
7.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { test, after, beforeEach } from 'node:test'
import assert from 'node:assert/strict'
import {
starteUmgebung, KUNDE_ID, PROJEKT_ID, TICKET_ID, ZWEITES_TICKET, LEAD_KUNDE, FREMD, VON, MELDUNG,
festpreisEingabe, aufwandEingabe, abgelehnt,
} from './helpers/auftraegeAb.js'
const umg = await starteUmgebung()
const { aw, config } = umg
after(() => umg.schliesse())
beforeEach(umg.zuruecksetzen)
const { getDocument } = await import('../server/services/appwriteAdmin.js')
const { getAuftrag, updateAuftrag } = await import('../server/services/auftraege/auftragStore.js')
const { legeEntwurfAn, aendereEntwurf, loescheEntwurf } = await import('../server/services/auftraege/auftraege.js')
const kundenartVon = async (id) => (await getDocument(config.collections.customers, id)).kundenart || ''
const FREMDES_PROJEKT = MELDUNG.projektFremd
const FREMDES_TICKET = 'Zeitquelle: Mindestens ein Ticket gehört nicht zu diesem Kunden.'
test('legeEntwurfAn: Festpreis-Entwurf mit Titel und Zeitquelle aus dem Projekt, Summe und Ersteller', async () => {
const a = await legeEntwurfAn(festpreisEingabe(), { von: VON })
assert.deepEqual([a.status, a.nummer, a.kundenId, a.projektId, a.titel], ['entwurf', '', KUNDE_ID, PROJEKT_ID, 'Website Beispiel'])
assert.deepEqual(a.zeitquelle, [TICKET_ID])
assert.deepEqual([a.art, a.summeCents, a.erstelltVon], ['festpreis', 80000, VON])
assert.deepEqual(a.zahlungsplan, { art: 'anzahlung', prozent: 50, text: '' })
assert.deepEqual(await getAuftrag(a.id), a)
})
test('legeEntwurfAn: ein eigener Titel gilt; ohne Projekt braucht es einen Titel', async () => {
assert.equal((await legeEntwurfAn(festpreisEingabe({ titel: ' Relaunch Phase 1 ' }), { von: VON })).titel, 'Relaunch Phase 1')
await abgelehnt(legeEntwurfAn(festpreisEingabe({ projektId: '' }), { von: VON }), 400, 'Titel: Bitte einen Titel angeben oder ein Projekt wählen.')
const frei = await legeEntwurfAn(festpreisEingabe({ projektId: '', titel: 'Logo-Entwurf' }), { von: VON })
assert.deepEqual([frei.projektId, frei.zeitquelle], ['', []])
})
test('legeEntwurfAn: Aufwand-Entwurf ohne Positionen und Summe, mit Stundensatz, Schätzung und gewählten Tickets', async () => {
const a = await legeEntwurfAn(aufwandEingabe({ zeitquelle: [TICKET_ID, ZWEITES_TICKET] }), { von: VON })
assert.deepEqual([a.art, a.positionen, a.summeCents, a.stundensatzCents, a.schaetzungMinuten], ['aufwand', [], null, 10000, 600])
assert.deepEqual(a.zeitquelle, [TICKET_ID, ZWEITES_TICKET])
assert.deepEqual(a.zahlungsplan, { art: 'monatlich', prozent: null, text: '' })
})
test('legeEntwurfAn: Entwürfe gibt es auch für Interessenten (nur das Senden ist festen Kunden vorbehalten)', async () => {
const a = await legeEntwurfAn(festpreisEingabe({ kundenId: LEAD_KUNDE, projektId: '', titel: 'Angebotsentwurf' }), { von: VON })
assert.deepEqual([a.kundenId, a.status], [LEAD_KUNDE, 'entwurf'])
})
test('kundenart aus der Eingabe wird am Kunden gespeichert – aber nur, wenn dort noch keine steht', async () => {
await legeEntwurfAn(festpreisEingabe({ kundenId: FREMD.kunde, projektId: FREMD.projekt, kundenart: 'privat' }), { von: VON })
assert.equal(await kundenartVon(FREMD.kunde), 'privat')
await legeEntwurfAn(festpreisEingabe({ kundenart: 'privat' }), { von: VON }) // der Kunde ist schon 'unternehmen'
assert.equal(await kundenartVon(KUNDE_ID), 'unternehmen')
await legeEntwurfAn(festpreisEingabe({ kundenId: LEAD_KUNDE, projektId: '', titel: 'x', kundenart: '' }), { von: VON })
assert.equal(await kundenartVon(LEAD_KUNDE), '')
})
test('fremde Bezüge werden abgelehnt, ohne dass etwas gespeichert wird (auch nicht die Kundenart)', async () => {
const eingabe = (patch) => festpreisEingabe({ kundenId: FREMD.kunde, projektId: FREMD.projekt, kundenart: 'privat', ...patch })
const faelle = [
['Projekt eines anderen Kunden', { projektId: PROJEKT_ID }, FREMDES_PROJEKT],
['unbekanntes Projekt', { projektId: 'p_gibtsnicht' }, FREMDES_PROJEKT],
['Ticket eines anderen Kunden', { zeitquelle: [TICKET_ID] }, FREMDES_TICKET],
['ein Ticket unbekannt', { zeitquelle: [FREMD.ticket, 't_gibtsnicht'] }, FREMDES_TICKET],
]
for (const [name, patch, meldung] of faelle) await abgelehnt(legeEntwurfAn(eingabe(patch), { von: VON }), 400, meldung, name)
assert.equal(aw.docs(config.collections.auftraege).size, 0)
assert.equal(await kundenartVon(FREMD.kunde), '')
})
test('Kunde: ohne Kennung 400, unbekannt 404, Kennung mit Sonderzeichen 404', async () => {
await abgelehnt(legeEntwurfAn(festpreisEingabe({ kundenId: undefined }), { von: VON }), 400, 'Kunde: Bitte einen Kunden angeben.')
await abgelehnt(legeEntwurfAn(festpreisEingabe({ kundenId: 'c_gibtsnicht' }), { von: VON }), 404, MELDUNG.kundeFehlt)
await abgelehnt(legeEntwurfAn(festpreisEingabe({ kundenId: '../users' }), { von: VON }), 404, MELDUNG.kundeFehlt)
})
test('status, nummer, Token und Ersteller aus der Eingabe werden ignoriert', async () => {
const a = await legeEntwurfAn(
{ ...festpreisEingabe(), status: 'bestaetigt', nummer: 'AB-2026-0001', jahr: 2026, tokenHash: 'abc', ersetztId: 'a_alt', erstelltVon: 'boese@example.invalid', pdfDatei: 'x/y.pdf' },
{ von: VON },
)
assert.deepEqual([a.status, a.nummer, a.jahr, a.erstelltVon], ['entwurf', '', null, VON])
assert.ok(!a.tokenHash && !a.ersetztId && !a.pdfDatei)
})
test('aendereEntwurf: nur die genannten Felder ändern sich, der Rest bleibt', async () => {
const a = await legeEntwurfAn(festpreisEingabe(), { von: VON })
const b = await aendereEntwurf(a.id, { titel: 'Neuer Titel', zahlungszielTage: 30 })
assert.deepEqual([b.titel, b.zahlungszielTage, b.summeCents], ['Neuer Titel', 30, 80000])
assert.deepEqual([b.positionen, b.zahlungsplan, b.zeitquelle], [a.positionen, a.zahlungsplan, a.zeitquelle])
assert.deepEqual(await getAuftrag(a.id), b)
})
test('aendereEntwurf: Wechsel der Art prüft das Ganze (Anzahlung geht nicht bei Aufwand), mit passendem Plan klappt er', async () => {
const a = await legeEntwurfAn(festpreisEingabe(), { von: VON })
await abgelehnt(aendereEntwurf(a.id, { art: 'aufwand' }), 400, 'Zahlungsplan: Eine Anzahlung geht nur bei einem Festpreis.')
assert.equal((await getAuftrag(a.id)).art, 'festpreis')
const b = await aendereEntwurf(a.id, { art: 'aufwand', stundensatzCents: 12000, zahlungsplan: { art: 'monatlich' } })
assert.deepEqual([b.art, b.positionen, b.summeCents, b.stundensatzCents, b.schaetzungMinuten], ['aufwand', [], null, 12000, null])
})
test('aendereEntwurf: Kunde lässt sich nicht wechseln, fremdes Projekt wird abgelehnt, unbekannte Aufträge sind 404', async () => {
const a = await legeEntwurfAn(festpreisEingabe(), { von: VON })
await abgelehnt(aendereEntwurf(a.id, { kundenId: FREMD.kunde }), 400, 'Kunde: Der Kunde eines Auftrags lässt sich nicht ändern.')
assert.equal((await aendereEntwurf(a.id, { kundenId: KUNDE_ID, titel: 'Gleicher Kunde' })).titel, 'Gleicher Kunde')
await abgelehnt(aendereEntwurf(a.id, { projektId: FREMD.projekt }), 400, FREMDES_PROJEKT)
await abgelehnt(aendereEntwurf('a_gibtsnicht', { titel: 'x' }), 404, MELDUNG.auftragFehlt)
await abgelehnt(aendereEntwurf('../x', { titel: 'x' }), 404, MELDUNG.auftragFehlt)
})
test('Ändern und Löschen gibt es nur für Entwürfe (409); Löschen entfernt den Entwurf', async () => {
const a = await legeEntwurfAn(festpreisEingabe(), { von: VON })
await updateAuftrag(a.id, { status: 'versendet', nummer: 'AB-2026-0001', jahr: 2026, laufnummer: 1 })
await abgelehnt(aendereEntwurf(a.id, { titel: 'Nachträglich' }), 409, MELDUNG.nurEntwurfAendern)
await abgelehnt(loescheEntwurf(a.id), 409, MELDUNG.nurEntwurfLoeschen)
assert.equal((await getAuftrag(a.id)).titel, 'Website Beispiel')
const b = await legeEntwurfAn(festpreisEingabe(), { von: VON })
await loescheEntwurf(b.id)
assert.equal(await getAuftrag(b.id), null)
await abgelehnt(loescheEntwurf(b.id), 404, MELDUNG.auftragFehlt)
})