Rechnungen: Sperre je Kunde gegen doppelte Abrechnung (Aufwand, Anzahlung, Schluss)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
ClaudeandClaude Sonnet 5.5 committed 2026-10-07 14:17:11 +00:00
1 parent d264f2af5a
commit ab3e6938da
2 files changed
+46 -2

No files matched your search

+40
View File
@@ -163,3 +163,43 @@ test('rechnungsVorschau: dieselben Prüfungen wie das Anlegen; Anzahlung ohne An
assert.deepEqual([v.summeCents, v.positionen[0].schluessel], [40000, 'anzahlung'])
assert.equal(aw.docs(config.collections.projektRechnungen).size, 1, 'nur der Entwurf von oben')
})
test('Aufwand: zwei gleichzeitige Rechnungen mit denselben Blättern -> genau eine entsteht, die andere bekommt 409', async () => {
st.delayNext({ method: 'POST', path: '/v1/invoices', ms: 150 })
const eingabe = (memo) => ({ customerId: 'k1', art: 'aufwand', projektId: 'p1', arbeitsblattIds: ['ws1', 'ws2'], memo, createdBy: 'k' })
const ergebnisse = await Promise.allSettled([createProjectInvoice(eingabe('Admin A')), createProjectInvoice(eingabe('Admin B'))])
assert.deepEqual(ergebnisse.map((e) => e.status), ['fulfilled', 'rejected'])
assert.equal(ergebnisse[1].reason.status, 409)
assert.equal(ergebnisse[1].reason.message, 'Arbeitsblatt bereits abgerechnet (Entwurf).')
assert.equal(st.invoices.size, 1)
assert.equal(callsTo('POST', '/v1/invoices').length, 1)
assert.equal(aw.docs(config.collections.projektRechnungen).size, 1)
})
test('Aufwand: eine nur teilweise überschneidende Auswahl wird abgewiesen, die übrigen Blätter bleiben frei', async () => {
const eingabe = (ids, memo) => ({ customerId: 'k1', art: 'aufwand', projektId: 'p1', arbeitsblattIds: ids, memo })
await createProjectInvoice(eingabe(['ws1', 'ws2'], 'A'))
await wirft(createProjectInvoice(eingabe(['ws2', 'ws3'], 'B')), 409, 'Arbeitsblatt bereits abgerechnet (Entwurf).')
const rest = await createProjectInvoice(eingabe(['ws3'], 'C'))
assert.equal(rest.totalCents, 10000)
assert.equal(st.invoices.size, 2)
})
test('Doppelklick (gleicher Inhalt gleichzeitig): der Schutz vor doppeltem Anlegen greift, es entsteht eine Rechnung', async () => {
const eingabe = { customerId: 'k1', art: 'aufwand', projektId: 'p1', arbeitsblattIds: ['ws1'] }
const ergebnisse = await Promise.allSettled([createProjectInvoice(eingabe), createProjectInvoice(eingabe)])
assert.deepEqual(ergebnisse.map((e) => e.status), ['fulfilled', 'rejected'])
assert.equal(ergebnisse[1].reason.message, 'Diese Rechnung wird gerade schon erstellt.')
assert.equal(st.invoices.size, 1)
})
test('Schluss: zwei gleichzeitige Schlussrechnungen zur selben AB -> eine entsteht, die andere stößt auf den Entwurf (409)', async () => {
const ab = await legeAuftragAn()
st.delayNext({ method: 'POST', path: '/v1/invoices', ms: 150 })
const eingabe = (memo) => ({ customerId: 'k1', art: 'schluss', auftragId: ab.id, memo })
const ergebnisse = await Promise.allSettled([createProjectInvoice(eingabe('A')), createProjectInvoice(eingabe('B'))])
assert.deepEqual(ergebnisse.map((e) => e.status), ['fulfilled', 'rejected'])
assert.equal(ergebnisse[1].reason.status, 409)
assert.equal(ergebnisse[1].reason.message, `Erst den Entwurf über 800,00${NBSP}€ senden oder löschen.`)
assert.equal(st.invoices.size, 1)
})