import { test } from 'node:test' import assert from 'node:assert/strict' import { useTestEnv } from './support/testEnv.js' import { beispielAuftrag, beispielSettings } from './auftraegePdfHilfe.js' useTestEnv({ appwriteUrl: 'http://127.0.0.1:1', stripeUrl: 'http://127.0.0.1:1' }) const { auftragPdfDaten, PDF_BESCHRIFTUNG, bereinigeTexte } = await import('../server/services/auftraege/pdf.js') const { AB_TEXTE, WIDERRUFSBELEHRUNG_PROJEKT, WIDERRUFSFORMULAR } = await import('../server/services/auftraege/texte.js') const { zahlungsplanText, aufwandText } = await import('../server/services/auftraege/auftragSicht.js') const { AuftragError } = await import('../server/services/auftraege/fehler.js') const { euroDe } = await import('../server/services/finance/format.js') const JETZT = new Date('2026-10-06T10:00:00.000Z') const NBSP = String.fromCodePoint(0xa0) const FRUEHBEGINN_SATZ = 'Ohne Ihr ausdrückliches Verlangen beginnen wir erst nach Ablauf der Widerrufsfrist.' // V7: AB_TEXTE.termine bei Privatpersonen const daten = (extra = {}, optionen = {}) => auftragPdfDaten(beispielAuftrag(extra), { settings: beispielSettings, jetzt: JETZT, ...optionen }) const aufwandAuftrag = { art: 'aufwand', positionen: [], summeCents: null, stundensatzCents: 10000, schaetzungMinuten: 600, zahlungsplan: { art: 'monatlich', prozent: null, text: '' } } test('euroDe liefert Beträge mit geschütztem Leerzeichen vor dem €-Zeichen (Grundlage aller Betragsvergleiche hier)', () => { assert.equal(euroDe(60000), `600,00${NBSP}€`) }) test('Festpreis: Kopf, Anschrift, Angaben und Positionen sind fertig formatiert', () => { const d = daten() assert.equal(d.vorschau, false) assert.equal(d.titel, AB_TEXTE.titel) assert.equal(d.nummer, 'AB-2026-0007') assert.equal(d.datum, '06.10.2026') assert.equal(d.kundennummer, 'K-1042') assert.equal(d.projekt, 'Neue Website Müller Bäckerei') assert.deepEqual(d.absender.zeilen, [ 'WEBklar GbR', 'Am Schwimmbad 10', '67722 Winnweiler', 'Telefon 0176 23726355', 'support@webklar.com', 'webklar.com', 'Steuernummer 12/345/67890', ]) assert.equal(d.absender.rueckzeile, 'WEBklar GbR · Am Schwimmbad 10 · 67722 Winnweiler') assert.deepEqual(d.empfaenger, ['Müller Bäckerei GmbH', 'Anna Müller', 'Hauptstraße 12', '67722 Winnweiler']) assert.equal(d.einleitung, AB_TEXTE.einleitung({ datum: '05.10.2026', weg: 'telefonisch' })) assert.ok(d.einleitung.includes('05.10.2026') && d.einleitung.includes('telefonisch')) assert.equal(d.leistung.art, 'festpreis') assert.equal(d.leistung.ueberschrift, 'Leistungsumfang') assert.deepEqual(d.leistung.positionen, [ { nr: '1', beschreibung: 'Gestaltung und Umsetzung der Website (5 Seiten)', menge: '1', einzelpreis: euroDe(60000), summe: euroDe(60000) }, { nr: '2', beschreibung: 'Kontaktformular mit E-Mail-Versand', menge: '2', einzelpreis: euroDe(10000), summe: euroDe(20000) }, ]) assert.deepEqual(d.leistung.gesamt, { label: 'Gesamtpreis', betrag: euroDe(80000) }) assert.equal(d.leistung.aufwandText, null) assert.equal(d.kleinunternehmer, 'Gemäß § 19 UStG wird keine Umsatzsteuer berechnet.') assert.deepEqual(PDF_BESCHRIFTUNG.spalten, ['Pos.', 'Beschreibung', 'Menge', 'Einzelpreis', 'Summe']) }) test('Datum der AB ist der Berliner Tag von gesendetAm, ohne gesendetAm der heutige Berliner Tag', () => { assert.equal(daten({ gesendetAm: '2026-10-06T22:30:00.000Z' }).datum, '07.10.2026') assert.equal(daten({ gesendetAm: '2026-10-06T21:30:00+00:00' }).datum, '06.10.2026') assert.equal(daten({ gesendetAm: null }, { jetzt: new Date('2026-12-31T23:30:00.000Z') }).datum, '01.01.2027') }) test('Aufwand: Aufwandsregel statt Positionen, keine Gesamtsumme', () => { const auftrag = beispielAuftrag(aufwandAuftrag) const d = auftragPdfDaten(auftrag, { settings: beispielSettings, jetzt: JETZT }) assert.equal(d.leistung.art, 'aufwand') assert.deepEqual(d.leistung.positionen, []) assert.equal(d.leistung.gesamt, null) assert.equal(d.leistung.aufwandText, aufwandText(auftrag)) assert.ok(d.leistung.aufwandText.includes(euroDe(10000))) assert.equal(d.kleinunternehmer, AB_TEXTE.kleinunternehmer) }) test('Vorschau: Nummer „Entwurf“, heutiges Datum, Kennzeichnung; ohne Vorschau braucht die AB eine Nummer', () => { const entwurf = { nummer: '', gesendetAm: null } const d = daten(entwurf, { vorschau: true }) assert.equal(d.vorschau, true) assert.equal(d.nummer, 'Entwurf') assert.equal(d.datum, '06.10.2026') assert.equal(d.beschriftung.entwurf, 'ENTWURF') assert.throws(() => daten(entwurf), (e) => e instanceof AuftragError && e.status === 409 && /Nummer/.test(e.message)) }) test('Anschrift: Firma und Name nur einmal, Land nur außerhalb Deutschlands, leere Teile entfallen', () => { const kunde = (extra) => ({ ...beispielAuftrag().kunde, ...extra }) assert.deepEqual(daten({ kunde: kunde({ firma: 'Anna Müller' }) }).empfaenger, ['Anna Müller', 'Hauptstraße 12', '67722 Winnweiler']) assert.deepEqual(daten({ kunde: kunde({ land: 'Österreich', plz: '1010', ort: 'Wien' }) }).empfaenger, ['Müller Bäckerei GmbH', 'Anna Müller', 'Hauptstraße 12', '1010 Wien', 'Österreich']) assert.deepEqual(daten({ kunde: kunde({ firma: '', land: '', strasse: '' }) }).empfaenger, ['Anna Müller', '67722 Winnweiler']) }) test('Fehlende Pflichtangaben und falsche Summe: AuftragError 409 mit Klartext statt kaputtem PDF', () => { const faelle = [ [{ kunde: null }, /Kundendaten/], [{ titel: ' ' }, /Titel/], [{ auftragVom: '' }, /Datum der Absprache/], [{ auftragWeg: 'brieftaube' }, /Weg der Absprache/], [{ art: 'pauschal' }, /Art des Auftrags/], [{ zahlungsplan: null }, /Zahlungsplan/], [{ positionen: [], summeCents: 0 }, /Positionen/], [{ summeCents: 79999 }, /Summe der Positionen/], [{ ...aufwandAuftrag, stundensatzCents: null }, /Stundensatz/], ] for (const [extra, muster] of faelle) { assert.throws(() => daten(extra, { vorschau: true }), (e) => e instanceof AuftragError && e.status === 409 && muster.test(e.message), JSON.stringify(extra)) } })