feat(accounting): Pflichtangaben der E-Rechnung vor dem Fertigstellen durchsetzen
All checks were successful
Build and Release FEDEO / verify (push) Successful in 59s
Build and Release FEDEO / build-and-release (push) Successful in 6m27s

Fehlende Pflichtangaben (Firmendaten, Steuer-ID, Kundenanschrift, IBAN,
§ 13b-USt-Id, Lastschriftmandat) erscheinen im Editor als blockierende
Fehler und verhindern Vorschau und Fertigstellung. Serienrechnungslauf,
MCP-Finalisierung und PDF-Erzeugung prüfen serverseitig vor der
Nummernvergabe bzw. Ablage.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-11-04 11:24:28 +01:00
parent 549b469a41
commit e9697ef197
7 changed files with 224 additions and 55 deletions

View File

@@ -1131,8 +1131,54 @@ const checkAddressZip = async () => {
}
}
// Pflichtangaben der E-Rechnung (ZUGFeRD) prüft das Backend, da Firmen- und Kundendaten dort vollständig vorliegen
const eInvoiceDocumentTypes = ["invoices", "advanceInvoices", "cancellationInvoices", "serialInvoices"]
const eInvoiceIssues = ref([])
const eInvoiceCheckSource = computed(() => {
if (!loaded.value || isTemplateMode.value || !eInvoiceDocumentTypes.includes(itemInfo.value.type)) return null
const item = itemInfo.value
return JSON.stringify({
type: item.type,
customer: item.customer,
contact: item.contact,
project: item.project,
contract: item.contract,
address: item.address,
rows: item.rows,
taxType: item.taxType,
payment_type: item.payment_type,
outgoingsepamandate: item.outgoingsepamandate,
deliveryDateType: item.deliveryDateType,
usedAdvanceInvoices: item.usedAdvanceInvoices,
createddocument: item.createddocument,
created_by: item.created_by,
})
})
const refreshEInvoiceIssues = async () => {
const source = eInvoiceCheckSource.value
if (!source) {
eInvoiceIssues.value = []
return eInvoiceIssues.value
}
try {
const result = await useNuxtApp().$api("/api/functions/einvoice/check", {
method: "POST",
body: { document: JSON.parse(source) },
})
// Nur übernehmen, wenn sich der Beleg während der Anfrage nicht geändert hat
if (source === eInvoiceCheckSource.value) eInvoiceIssues.value = result?.issues || []
} catch (error) {
console.error(error)
eInvoiceIssues.value = [{ message: "E-Rechnung: Die Pflichtangaben konnten nicht geprüft werden", type: "breaking" }]
}
return eInvoiceIssues.value
}
watchDebounced(eInvoiceCheckSource, refreshEInvoiceIssues, { debounce: 500, immediate: true })
const findDocumentErrors = computed(() => {
let errors = []
let errors = [...eInvoiceIssues.value]
if (itemInfo.value.customer === null) errors.push({message: "Es ist kein Kunde ausgewählt", type: "breaking"})
if (itemInfo.value.contact === null) errors.push({message: "Es ist kein Kontakt ausgewählt", type: "info"})
@@ -2025,6 +2071,18 @@ const saveFinalizedCostCentres = async () => {
const selectedTab = ref("0")
const closeDocument = async () => {
// Vor Vorschau und Fertigstellung mit dem aktuellen Stand prüfen, nicht mit dem letzten (entprellten) Ergebnis
await refreshEInvoiceIssues()
const breakingErrors = findDocumentErrors.value.filter(i => i.type === "breaking")
if (breakingErrors.length > 0) {
selectedTab.value = "0"
toast.add({
title: "Beleg kann nicht fertiggestellt werden",
description: breakingErrors.map(i => i.message).join(" · "),
color: "error",
})
return
}
if(selectedTab.value === "0") {
await generateDocument()
@@ -2034,7 +2092,16 @@ const closeDocument = async () => {
await saveDocument("Gebucht")
await uploadGeneratedDocument()
try {
await uploadGeneratedDocument()
} catch (error) {
console.error(error)
toast.add({
title: "PDF bzw. E-Rechnung konnte nicht erstellt werden",
description: error?.data?.error || error?.message,
color: "error",
})
}
guard.value = false
@@ -2052,13 +2119,8 @@ const uploadGeneratedDocument = async () => {
await generateDocument({
createdDocumentId: itemInfo.value.id,
onResult: (result) => {
if (result?.einvoiceWarnings?.length) {
toast.add({
title: result.einvoice ? "E-Rechnung mit Hinweisen erstellt" : "E-Rechnung konnte nicht erstellt werden",
description: result.einvoiceWarnings.join(" · "),
color: "warning",
})
}
const hints = (result?.einvoiceIssues || []).map(i => i.message)
if (hints.length) toast.add({ title: "E-Rechnung mit Hinweisen erstellt", description: hints.join(" · "), color: "warning" })
},
})