161 lines
7.5 KiB
JavaScript
161 lines
7.5 KiB
JavaScript
import test from 'node:test'
|
||
import assert from 'node:assert/strict'
|
||
import { loadModule } from './load.mjs'
|
||
|
||
const {
|
||
STRIPE_HINWEIS, KEINE_PROJEKTE_HINWEIS,
|
||
stundenDe, satzText, ticketsText, stripeHinweis, vereinbartText, kontoZeile, ohneProjektZeile,
|
||
artLabel, projektSpalte, abgerechnetText, abgerechnetWarnung, ticketIdsOf,
|
||
} = await loadModule('src/lib/projektkontoView.js')
|
||
|
||
const konto = (over = {}) => ({
|
||
projektId: 'p1',
|
||
name: 'Website Relaunch',
|
||
projektTyp: 'Website',
|
||
tickets: [{ id: 't1', woid: '100131' }],
|
||
zeitquelle: ['t1'],
|
||
vereinbart: { festpreisCents: 120000, aufwand: null },
|
||
berechnetCents: 50000,
|
||
bezahltCents: 20000,
|
||
offenCents: 70000,
|
||
zeit: { minuten: 750, aboMinuten: 0, offeneMinuten: 750, satzCents: 10000, wertCents: 125000, offenerWertCents: 125000 },
|
||
...over,
|
||
})
|
||
const AUFWAND = { festpreisCents: null, aufwand: { stundensatzCents: 10000, schaetzungMinuten: 600 } }
|
||
|
||
test('stundenDe: Dezimalstunden mit Komma, ohne überflüssige Nullen', () => {
|
||
assert.equal(stundenDe(750), '12,5 Std.')
|
||
assert.equal(stundenDe(135), '2,25 Std.')
|
||
assert.equal(stundenDe(60), '1 Std.')
|
||
assert.equal(stundenDe(20), '0,33 Std.')
|
||
assert.equal(stundenDe(0), '0 Std.')
|
||
assert.equal(stundenDe(null), '0 Std.')
|
||
assert.equal(stundenDe('abc'), '0 Std.')
|
||
})
|
||
|
||
test('satzText: ganze Euro ohne Cent, sonst mit Cent', () => {
|
||
assert.equal(satzText(10000), '100 €/Std.')
|
||
assert.equal(satzText(8550), '85,50 €/Std.')
|
||
assert.equal(satzText(null), '–')
|
||
})
|
||
|
||
test('ticketsText: Ticketnummern mit Raute, ohne Nummer fällt der Eintrag weg', () => {
|
||
assert.equal(ticketsText([{ id: 'a', woid: '100131' }]), '#100131')
|
||
assert.equal(ticketsText([{ id: 'a', woid: '100131' }, { id: 'b', woid: '100140' }]), '#100131, #100140')
|
||
assert.equal(ticketsText([{ id: 'a' }, null]), '')
|
||
assert.equal(ticketsText(undefined), '')
|
||
})
|
||
|
||
test('vereinbartText: Festpreis, Aufwand mit Schätzung, beides, keine AB', () => {
|
||
assert.equal(vereinbartText({ festpreisCents: 120000, aufwand: null }), '1.200,00 €')
|
||
assert.equal(vereinbartText(AUFWAND), 'nach Aufwand, 100 €/Std., Schätzung 10 Std.')
|
||
assert.equal(vereinbartText({ festpreisCents: null, aufwand: { stundensatzCents: 8550, schaetzungMinuten: null } }), 'nach Aufwand, 85,50 €/Std.')
|
||
assert.equal(vereinbartText({ festpreisCents: 120000, aufwand: { stundensatzCents: 10000, schaetzungMinuten: null } }), '1.200,00 € und nach Aufwand, 100 €/Std.')
|
||
assert.equal(vereinbartText({ festpreisCents: null, aufwand: null }), 'keine AB')
|
||
assert.equal(vereinbartText(undefined), 'keine AB')
|
||
})
|
||
|
||
test('kontoZeile: Festpreis-AB mit Berechnet, bezahlt, Noch offen und Zeit', () => {
|
||
assert.deepEqual(kontoZeile(konto()), {
|
||
key: 'p1',
|
||
projektId: 'p1',
|
||
name: 'Website Relaunch',
|
||
meta: 'Website · #100131',
|
||
vereinbart: '1.200,00 €',
|
||
berechnet: '500,00 €',
|
||
bezahlt: 'bezahlt 200,00 €',
|
||
offen: '700,00 €',
|
||
zeit: { stunden: '12,5 Std.', wert: 'Wert 1.250,00 €', abo: '' },
|
||
})
|
||
// ohne Art und ohne Ticket bleibt nur der Name
|
||
assert.equal(kontoZeile(konto({ projektTyp: '', tickets: [] })).meta, '')
|
||
})
|
||
|
||
test('kontoZeile: Aufwand-AB (Noch offen = Wert der offenen Zeit) und Abo-Zeit getrennt', () => {
|
||
const z = kontoZeile(konto({
|
||
vereinbart: AUFWAND,
|
||
offenCents: null,
|
||
zeit: { minuten: 300, aboMinuten: 90, offeneMinuten: 180, satzCents: 10000, wertCents: 50000, offenerWertCents: 30000 },
|
||
}))
|
||
assert.equal(z.vereinbart, 'nach Aufwand, 100 €/Std., Schätzung 10 Std.')
|
||
assert.equal(z.offen, '300,00 €')
|
||
assert.deepEqual(z.zeit, { stunden: '5 Std.', wert: 'Wert 500,00 €', abo: 'über Abo: 1,5 Std.' })
|
||
})
|
||
|
||
test('kontoZeile: ohne AB steht „keine AB“ und Noch offen ist „–“', () => {
|
||
const z = kontoZeile(konto({ vereinbart: { festpreisCents: null, aufwand: null }, offenCents: null }))
|
||
assert.equal(z.vereinbart, 'keine AB')
|
||
assert.equal(z.offen, '–')
|
||
})
|
||
|
||
test('kontoZeile: Stripe nicht erreichbar zeigt „–“ statt Nullen, Zeit und Vereinbartes bleiben', () => {
|
||
const z = kontoZeile(konto({ berechnetCents: 0, bezahltCents: 0, offenCents: null }), { stripeOk: false })
|
||
assert.deepEqual([z.vereinbart, z.berechnet, z.bezahlt, z.offen], ['1.200,00 €', '–', '', '–'])
|
||
assert.equal(z.zeit.wert, 'Wert 1.250,00 €')
|
||
// Aufwand: der Wert der offenen Zeit braucht kein Stripe
|
||
const a = kontoZeile(konto({ vereinbart: AUFWAND, offenCents: null }), { stripeOk: false })
|
||
assert.equal(a.offen, '1.250,00 €')
|
||
assert.equal(stripeHinweis(false), STRIPE_HINWEIS)
|
||
assert.equal(stripeHinweis(true), '')
|
||
assert.equal(stripeHinweis(undefined), '')
|
||
assert.equal(STRIPE_HINWEIS, 'Stripe ist gerade nicht erreichbar. Berechnete und bezahlte Beträge sind deshalb nicht verfügbar.')
|
||
})
|
||
|
||
test('ohneProjektZeile: Rechnungen ohne Projekt, ohne Vereinbart und Zeit', () => {
|
||
assert.deepEqual(ohneProjektZeile({ berechnetCents: 30000, bezahltCents: 10000, anzahl: 3 }), {
|
||
key: 'ohne-projekt',
|
||
projektId: '',
|
||
name: 'Ohne Projekt',
|
||
meta: '3 Rechnungen',
|
||
vereinbart: '–',
|
||
berechnet: '300,00 €',
|
||
bezahlt: 'bezahlt 100,00 €',
|
||
offen: '–',
|
||
zeit: { stunden: '–', wert: '', abo: '' },
|
||
})
|
||
assert.equal(ohneProjektZeile({ berechnetCents: 0, bezahltCents: 0, anzahl: 1 }).meta, '1 Rechnung')
|
||
assert.equal(ohneProjektZeile({ berechnetCents: 0, bezahltCents: 0, anzahl: 0 }).meta, 'keine Rechnungen')
|
||
assert.equal(ohneProjektZeile(undefined).meta, 'keine Rechnungen')
|
||
const s = ohneProjektZeile({ berechnetCents: 30000, bezahltCents: 10000, anzahl: 3 }, { stripeOk: false })
|
||
assert.deepEqual([s.berechnet, s.bezahlt], ['–', ''])
|
||
})
|
||
|
||
test('Hinweis für Kunden ohne Projekte', () => {
|
||
assert.equal(KEINE_PROJEKTE_HINWEIS, 'Dieser Kunde hat noch keine Projekte. Rechnungen entstehen ohne Projektbezug.')
|
||
})
|
||
|
||
test('artLabel: Spalte Art der Rechnungstabelle', () => {
|
||
assert.deepEqual(
|
||
['frei', 'festbetrag', 'aufwand', 'anzahlung', 'schluss', 'abo'].map((a) => artLabel(a)),
|
||
['Ohne Projekt', 'Festbetrag', 'Aufwand', 'Anzahlung', 'Schlussrechnung', 'Abo']
|
||
)
|
||
assert.equal(artLabel(undefined), '–')
|
||
assert.equal(artLabel('unbekannt'), '–')
|
||
assert.equal(artLabel('constructor'), '–')
|
||
})
|
||
|
||
test('projektSpalte: Projektname der Rechnung oder „–“', () => {
|
||
assert.equal(projektSpalte({ projektName: ' Website Relaunch ' }), 'Website Relaunch')
|
||
assert.equal(projektSpalte({ projektName: '' }), '–')
|
||
assert.equal(projektSpalte({}), '–')
|
||
assert.equal(projektSpalte(null), '–')
|
||
})
|
||
|
||
test('abgerechnetText und abgerechnetWarnung: Rechnungsnummer oder Entwurf', () => {
|
||
const map = { w1: 'WEBKLAR-0009', w2: 'Entwurf' }
|
||
assert.equal(abgerechnetText(map, 'w1'), 'abgerechnet (WEBKLAR-0009)')
|
||
assert.equal(abgerechnetText(map, 'w2'), 'abgerechnet (Entwurf)')
|
||
assert.equal(abgerechnetText(map, 'w3'), null)
|
||
assert.equal(abgerechnetText(map, 'constructor'), null)
|
||
assert.equal(abgerechnetText(null, 'w1'), null)
|
||
assert.equal(abgerechnetWarnung(map, 'w1'), 'Dieses Arbeitsblatt ist abgerechnet (WEBKLAR-0009). Eine Änderung ändert die Rechnung nicht.')
|
||
assert.equal(abgerechnetWarnung(map, 'w2'), 'Dieses Arbeitsblatt ist abgerechnet (Entwurf). Eine Änderung ändert die Rechnung nicht.')
|
||
assert.equal(abgerechnetWarnung(map, 'w3'), null)
|
||
})
|
||
|
||
test('ticketIdsOf: eindeutige Ticket-Kennungen der Arbeitsblätter, höchstens fünf', () => {
|
||
assert.deepEqual(ticketIdsOf([{ workorderId: 't1' }, { workorderId: 't1' }, { workorderId: 't2' }, {}, null]), ['t1', 't2'])
|
||
assert.deepEqual(ticketIdsOf(undefined), [])
|
||
assert.equal(ticketIdsOf(Array.from({ length: 7 }, (_, i) => ({ workorderId: `t${i}` }))).length, 5)
|
||
})
|