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) })