AB-Kern: Neue Fassung und Ersetzen der alten AB beim Senden
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
0da5b30119
commit
cf87a7e1e0
2 files changed
+156
-2
No files matched your search
@@ -12,12 +12,13 @@ import { getSettings } from '../finance/settings.js'
|
||||
import { withLocks } from '../keyedLock.js'
|
||||
import { kundeSnapshot } from './auftragSicht.js'
|
||||
import { entfernePdf, lesePdf, speicherePdf } from './ablage.js'
|
||||
import { createAuftrag, deleteAuftrag, getAuftrag, updateAuftrag } from './auftragStore.js'
|
||||
import { createAuftrag, deleteAuftrag, getAuftrag, listAuftraege, updateAuftrag } from './auftragStore.js'
|
||||
import { AuftragError } from './fehler.js'
|
||||
import { vergibNummer } from './nummern.js'
|
||||
import { umhaengen } from './projektRechnungenStore.js'
|
||||
import { TEXTE_FASSUNG } from './texte.js'
|
||||
import {
|
||||
AGB_FASSUNG, AUFTRAG_ARTEN, AUFTRAG_WEGE, KUNDENARTEN, LIMITS, SPERRE_NUMMER, sperreAuftrag, STUNDENSATZ_STANDARD_CENTS, VIERTELSTUNDE, ZAHLUNGSPLAN_ARTEN,
|
||||
AGB_FASSUNG, AUFTRAG_ARTEN, AUFTRAG_WEGE, KUNDENARTEN, LIMITS, SPERRE_NUMMER, sperreAuftrag, STUNDENSATZ_STANDARD_CENTS, VEREINBARTE_STATUS, VIERTELSTUNDE, ZAHLUNGSPLAN_ARTEN,
|
||||
} from './konstanten.js'
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
@@ -407,6 +408,33 @@ async function versendeMail(d, gespeichert, { pdf, token, erinnerung = false })
|
||||
return { auftrag: final, mailFehler: mailPatch.mailStatus === 'fehler' }
|
||||
}
|
||||
|
||||
const MELDUNG_ERSETZTE_UNGUELTIG = 'Die ersetzte Auftragsbestätigung ist nicht mehr gültig. Bitte eine neue Fassung anlegen.'
|
||||
|
||||
/**
|
||||
* Prüft die AB, die der Entwurf ersetzen soll: gültig sind versendet, bestätigt, abgerechnet oder (bei der Wiederholung
|
||||
* nach einem Fehler) schon durch genau diesen Entwurf ersetzt. Zeigt ersetztId auf den Entwurf selbst (beschädigte Daten),
|
||||
* gibt es sofort 409, damit ersetzeAlteAb nicht den schon gehaltenen Schlüssel noch einmal sperrt.
|
||||
*/
|
||||
async function pruefeErsetzteAb(entwurf) {
|
||||
if (entwurf.ersetztId === entwurf.id) throw new AuftragError(409, MELDUNG_ERSETZTE_UNGUELTIG)
|
||||
const alt = await getAuftrag(entwurf.ersetztId)
|
||||
const gueltig = alt && (VEREINBARTE_STATUS.includes(alt.status) || (alt.status === 'ersetzt' && alt.ersetztDurchId === entwurf.id))
|
||||
if (!gueltig) throw new AuftragError(409, MELDUNG_ERSETZTE_UNGUELTIG)
|
||||
return alt
|
||||
}
|
||||
|
||||
/**
|
||||
* Ersetzt die alte AB (Status ersetzt + ersetztDurchId) und hängt ihre Projektrechnungen um – vor dem Speichern der neuen
|
||||
* AB, wiederholbar. Der Stand der alten AB wird unter ihrer eigenen Sperre noch einmal geprüft; ihr tokenHash bleibt.
|
||||
*/
|
||||
async function ersetzeAlteAb(entwurf) {
|
||||
await withLocks(sperreAuftrag(entwurf.ersetztId), async () => {
|
||||
const alt = await pruefeErsetzteAb(entwurf)
|
||||
if (alt.status !== 'ersetzt') await updateAuftrag(alt.id, { status: 'ersetzt', ersetztDurchId: entwurf.id })
|
||||
await umhaengen(alt.id, entwurf.id)
|
||||
})
|
||||
}
|
||||
|
||||
export async function sendeAuftrag(id, { von, deps, jetzt = new Date() } = {}) {
|
||||
void von // wird nicht gespeichert (V1 hat kein Feld dafür); die Team-Kopie der Mail belegt den Versand
|
||||
const d = await ladeDeps(deps, ['erzeugeAuftragPdf', 'neuerToken', 'sendeAuftragMail'])
|
||||
@@ -417,6 +445,7 @@ export async function sendeAuftrag(id, { von, deps, jetzt = new Date() } = {}) {
|
||||
pruefeEingabe(eingabeAusAuftrag(entwurf))
|
||||
const kundeDoc = await ladeKunde(entwurf.kundenId)
|
||||
pruefeKundeFuerVersand(kundeDoc)
|
||||
if (entwurf.ersetztId) await pruefeErsetzteAb(entwurf) // früh: vor Nummer und PDF
|
||||
const kunde = kundeSnapshot(kundeDoc)
|
||||
const { steuernummer, bankDetailsText } = await getSettings()
|
||||
const { nummer, jahr, laufnummer } = await vergibNummer(jetzt)
|
||||
@@ -433,6 +462,7 @@ export async function sendeAuftrag(id, { von, deps, jetzt = new Date() } = {}) {
|
||||
}
|
||||
try {
|
||||
const neu = d.neuerToken(jetzt)
|
||||
if (entwurf.ersetztId) await ersetzeAlteAb(entwurf)
|
||||
const gespeichertesDokument = await updateAuftrag(entwurf.id, {
|
||||
status: 'versendet', nummer, jahr, laufnummer, kunde, gesendetAm, texteFassung: TEXTE_FASSUNG, agbFassung: AGB_FASSUNG,
|
||||
pdfDatei: ablage.pdfDatei, pdfSha256: ablage.pdfSha256, gesendetAn: kunde.email, tokenHash: neu.hash, tokenGueltigBis: neu.gueltigBis.toISOString(),
|
||||
@@ -480,3 +510,22 @@ export async function erinnereAuftrag(id, { deps, jetzt = new Date() } = {}) {
|
||||
})
|
||||
return versendeMail(d, gespeichert, { pdf, token, erinnerung })
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
// Neue Fassung
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
/** Legt aus einer versendeten, bestätigten oder abgerechneten AB einen neuen Entwurf an (ersetztId); die alte bleibt. */
|
||||
export async function neueFassung(id, { von } = {}) {
|
||||
return withLocks(sperreAuftrag(id), async () => {
|
||||
const alt = await ladeAuftrag(id)
|
||||
if (!VEREINBARTE_STATUS.includes(alt.status)) {
|
||||
throw new AuftragError(409, 'Eine neue Fassung gibt es nur für versendete, bestätigte oder abgerechnete Aufträge.')
|
||||
}
|
||||
const vorhandene = await listAuftraege({ kundenId: alt.kundenId })
|
||||
if (vorhandene.some((a) => a.status === 'entwurf' && a.ersetztId === alt.id)) {
|
||||
throw new AuftragError(409, 'Zu dieser Auftragsbestätigung gibt es schon einen Entwurf für eine neue Fassung.')
|
||||
}
|
||||
return createAuftrag({ kundenId: alt.kundenId, ...speicherFelder(alt), ersetztId: alt.id, erstelltVon: String(von || '') })
|
||||
})
|
||||
}
|
||||
Reference in new issue
Block a user