Bei Anzahlung, Schlussrechnung und Aufwand wird 'Zahlungsziel in Tagen' mit auftrag.zahlungszielTage vorbelegt (sonst 14); eine Eingabe des Nutzers bleibt. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
133 lines
6.6 KiB
JavaScript
133 lines
6.6 KiB
JavaScript
import test from 'node:test'
|
||
import assert from 'node:assert/strict'
|
||
import { loadModule } from './load.mjs'
|
||
|
||
const { anfangszustand, reduce } = await loadModule('src/lib/rechnungDialogState.js')
|
||
|
||
test('anfangszustand: nichts gewählt, eine leere Position, Zahlungsziel 14', () => {
|
||
assert.deepEqual(anfangszustand({ projektId: 'p1' }), {
|
||
projektId: 'p1', art: '', auftragId: '',
|
||
items: [{ uid: 1, description: '', quantity: '1', price: '' }], zusatz: [],
|
||
abgewaehlt: [], weitereTickets: [], anzahlung: {}, zeilentexte: {},
|
||
zeitraum: '', zeitraumGeaendert: false, days: '14', tageGeaendert: false, memo: '',
|
||
})
|
||
assert.equal(anfangszustand().projektId, null)
|
||
assert.equal(anfangszustand({ projektId: '' }).projektId, '')
|
||
})
|
||
|
||
test('projekt: setzt alles zurück, behält aber Zahlungsziel und Notiz', () => {
|
||
let s = anfangszustand({ projektId: 'p1' })
|
||
s = reduce(s, { type: 'tage', wert: '30' })
|
||
s = reduce(s, { type: 'notiz', wert: 'Danke' })
|
||
s = reduce(s, { type: 'art', art: 'aufwand' })
|
||
s = reduce(s, { type: 'blatt', id: 'b1' })
|
||
s = reduce(s, { type: 'zeilentext', schluessel: '2026-10-06', text: 'Neu', original: 'Alt' })
|
||
s = reduce(s, { type: 'projekt', projektId: 'p2' })
|
||
assert.equal(s.projektId, 'p2')
|
||
assert.equal(s.art, '')
|
||
assert.deepEqual(s.abgewaehlt, [])
|
||
assert.deepEqual(s.zeilentexte, {})
|
||
assert.equal(s.days, '30')
|
||
assert.equal(s.memo, 'Danke')
|
||
assert.equal(reduce(s, { type: 'projekt', projektId: null }).projektId, null)
|
||
})
|
||
|
||
test('art: Positionen für Festbetrag und Zusatzpositionen bleiben getrennt und erhalten', () => {
|
||
let s = anfangszustand({ projektId: 'p1' })
|
||
s = reduce(s, { type: 'position', liste: 'items', uid: 1, feld: 'description', wert: 'Pauschale' })
|
||
s = reduce(s, { type: 'position+', liste: 'zusatz' })
|
||
s = reduce(s, { type: 'position', liste: 'zusatz', uid: 2, feld: 'price', wert: '12,00' })
|
||
s = reduce(s, { type: 'art', art: 'aufwand' })
|
||
assert.equal(s.art, 'aufwand')
|
||
assert.equal(s.items[0].description, 'Pauschale')
|
||
assert.deepEqual(s.zusatz, [{ uid: 2, description: '', quantity: '1', price: '12,00' }])
|
||
// eine unbekannte Liste oder ein unbekanntes Feld ändert nichts
|
||
assert.equal(reduce(s, { type: 'position', liste: 'x', uid: 1, feld: 'description', wert: 'y' }), s)
|
||
assert.equal(reduce(s, { type: 'position', liste: 'items', uid: 1, feld: 'uid', wert: 9 }), s)
|
||
})
|
||
|
||
test('position+ und position-: Positionen mindestens 1, Zusatzpositionen mindestens 0, höchstens 20', () => {
|
||
let s = anfangszustand({ projektId: 'p1' })
|
||
assert.equal(reduce(s, { type: 'position-', liste: 'items', uid: 1 }), s)
|
||
s = reduce(s, { type: 'position+', liste: 'zusatz' })
|
||
assert.equal(s.zusatz[0].uid, 2)
|
||
s = reduce(s, { type: 'position-', liste: 'zusatz', uid: 2 })
|
||
assert.deepEqual(s.zusatz, [])
|
||
for (let i = 0; i < 25; i += 1) s = reduce(s, { type: 'position+', liste: 'zusatz' })
|
||
assert.equal(s.zusatz.length, 20)
|
||
})
|
||
|
||
test('blatt: Abwählen und Wiederanwählen', () => {
|
||
let s = anfangszustand({ projektId: 'p1' })
|
||
s = reduce(s, { type: 'blatt', id: 'b2' })
|
||
assert.deepEqual(s.abgewaehlt, ['b2'])
|
||
s = reduce(s, { type: 'blatt', id: 'b2' })
|
||
assert.deepEqual(s.abgewaehlt, [])
|
||
})
|
||
|
||
test('ticket+ und ticket-: ein Ticket nur einmal, beim Entfernen verschwindet die Abwahl seiner Blätter', () => {
|
||
const ticket = { ticketId: 't2', woid: '100140', titel: 'Kontaktformular' }
|
||
let s = anfangszustand({ projektId: 'p1' })
|
||
s = reduce(s, { type: 'ticket+', ticket })
|
||
s = reduce(s, { type: 'ticket+', ticket })
|
||
assert.deepEqual(s.weitereTickets, [ticket])
|
||
s = reduce(s, { type: 'blatt', id: 'w1' })
|
||
s = reduce(s, { type: 'blatt', id: 'b9' })
|
||
s = reduce(s, { type: 'ticket-', ticketId: 't2', blattIds: ['w1'] })
|
||
assert.deepEqual(s.weitereTickets, [])
|
||
assert.deepEqual(s.abgewaehlt, ['b9'])
|
||
})
|
||
|
||
test('zeitraum-vorschlag gilt nur, solange der Nutzer das Feld nicht selbst geändert hat', () => {
|
||
let s = anfangszustand({ projektId: 'p1' })
|
||
s = reduce(s, { type: 'zeitraum-vorschlag', text: '01.10.–20.10.2026' })
|
||
assert.deepEqual([s.zeitraum, s.zeitraumGeaendert], ['01.10.–20.10.2026', false])
|
||
assert.equal(reduce(s, { type: 'zeitraum-vorschlag', text: '01.10.–20.10.2026' }), s) // gleicher Text: kein neuer Zustand
|
||
s = reduce(s, { type: 'zeitraum', text: 'Oktober 2026' })
|
||
assert.deepEqual([s.zeitraum, s.zeitraumGeaendert], ['Oktober 2026', true])
|
||
assert.equal(reduce(s, { type: 'zeitraum-vorschlag', text: '02.10.–21.10.2026' }).zeitraum, 'Oktober 2026')
|
||
// ein Wechsel der Art verwirft einen Vorschlag, nicht aber die Eingabe des Nutzers
|
||
const vorschlag = reduce(anfangszustand({ projektId: 'p1' }), { type: 'zeitraum-vorschlag', text: '01.10.–20.10.2026' })
|
||
assert.equal(reduce(vorschlag, { type: 'art', art: 'festbetrag' }).zeitraum, '')
|
||
assert.equal(reduce(s, { type: 'art', art: 'festbetrag' }).zeitraum, 'Oktober 2026')
|
||
})
|
||
|
||
test('zeilentext: ein unveränderter oder leerer Text entfernt den Eintrag', () => {
|
||
let s = anfangszustand({ projektId: 'p1' })
|
||
const setze = (text) => reduce(s, { type: 'zeilentext', schluessel: '2026-10-06', text, original: 'Alt' })
|
||
s = setze('Neu')
|
||
assert.deepEqual(s.zeilentexte, { '2026-10-06': 'Neu' })
|
||
s = setze('Alt')
|
||
assert.deepEqual(s.zeilentexte, {})
|
||
s = setze('Neu')
|
||
s = setze(' ')
|
||
assert.deepEqual(s.zeilentexte, {})
|
||
})
|
||
|
||
test('anzahlung und auftrag: Eingaben ergänzen sich, eine andere AB setzt sie zurück', () => {
|
||
let s = anfangszustand({ projektId: 'p1' })
|
||
s = reduce(s, { type: 'anzahlung', patch: { modus: 'betrag' } })
|
||
s = reduce(s, { type: 'anzahlung', patch: { wert: '400,00' } })
|
||
assert.deepEqual(s.anzahlung, { modus: 'betrag', wert: '400,00' })
|
||
s = reduce(s, { type: 'auftrag', auftragId: 'a2' })
|
||
assert.deepEqual([s.auftragId, s.anzahlung], ['a2', {}])
|
||
assert.equal(reduce(s, { type: 'gibtsnicht' }), s)
|
||
})
|
||
|
||
test('tage-vorschlag: übernimmt das Zahlungsziel der AB, solange der Nutzer es nicht selbst geändert hat', () => {
|
||
let s = anfangszustand({ projektId: 'p1' })
|
||
s = reduce(s, { type: 'tage-vorschlag', wert: '30' })
|
||
assert.equal(s.days, '30')
|
||
assert.equal(s.tageGeaendert, false)
|
||
assert.equal(reduce(s, { type: 'tage-vorschlag', wert: '30' }), s) // derselbe Wert: nichts zu tun
|
||
s = reduce(s, { type: 'tage-vorschlag', wert: '14' }) // andere AB gewählt: der Vorschlag folgt
|
||
assert.equal(s.days, '14')
|
||
// eine Eingabe des Nutzers wird nie überschrieben, auch nicht nach einem Projektwechsel
|
||
s = reduce(s, { type: 'tage', wert: '7' })
|
||
assert.equal(s.tageGeaendert, true)
|
||
assert.equal(reduce(s, { type: 'tage-vorschlag', wert: '30' }), s)
|
||
s = reduce(s, { type: 'projekt', projektId: 'p2' })
|
||
assert.equal(s.days, '7')
|
||
assert.equal(reduce(s, { type: 'tage-vorschlag', wert: '30' }).days, '7')
|
||
})
|