diff --git a/frontend/pages/createDocument/edit/[[id]].vue b/frontend/pages/createDocument/edit/[[id]].vue index 70d2576b..d852c043 100644 --- a/frontend/pages/createDocument/edit/[[id]].vue +++ b/frontend/pages/createDocument/edit/[[id]].vue @@ -730,6 +730,12 @@ const setupPage = async () => { await router.replace('/createDocument') return } + + if (route.query.regeneratePdf && route.params.id) { + await regenerateMissingPdf() + return + } + loaded.value = true } @@ -1980,38 +1986,7 @@ const closeDocument = async () => { await saveDocument("Gebucht") - await generateDocument() - - let fileData = {} - - fileData.project = itemInfo.value.project - fileData.createddocument = itemInfo.value.id - - let mappedType = documentStorageFallbackTypes[itemInfo.value.type] || itemInfo.value.type - - const folders = await useEntities("folders").select() - console.log(folders) - fileData.folder = folders.find(i => i.function === mappedType && i.year === Number(dayjs().format("YYYY"))).id - - const tags = await useEntities("filetags").select() - console.log(tags) - fileData.type = tags.find(i => i.createdDocumentType === mappedType).id - - function dataURLtoFile(dataurl, filename) { - var arr = dataurl.split(","), - mime = arr[0].match(/:(.*?);/)[1], - bstr = atob(arr[arr.length - 1]), - n = bstr.length, - u8arr = new Uint8Array(n); - while (n--) { - u8arr[n] = bstr.charCodeAt(n); - } - return new File([u8arr], filename, {type: mime}); - } - - let file = dataURLtoFile(uri.value, `${itemInfo.value.documentNumber}.pdf`) - - await useFiles().uploadFiles(fileData, [file]) + await uploadGeneratedDocument() guard.value = false @@ -2021,6 +1996,77 @@ const closeDocument = async () => { +} + +// Erzeugt die PDF aus dem aktuellen Stand und hängt sie an den Beleg an, ohne den Datensatz zu speichern +const uploadGeneratedDocument = async () => { + await generateDocument() + + if (!uri.value) throw new Error("PDF konnte nicht erzeugt werden") + + let fileData = {} + + fileData.project = itemInfo.value.project + fileData.createddocument = itemInfo.value.id + + let mappedType = documentStorageFallbackTypes[itemInfo.value.type] || itemInfo.value.type + + const folders = await useEntities("folders").select() + console.log(folders) + fileData.folder = folders.find(i => i.function === mappedType && i.year === Number(dayjs().format("YYYY"))).id + + const tags = await useEntities("filetags").select() + console.log(tags) + fileData.type = tags.find(i => i.createdDocumentType === mappedType).id + + function dataURLtoFile(dataurl, filename) { + var arr = dataurl.split(","), + mime = arr[0].match(/:(.*?);/)[1], + bstr = atob(arr[arr.length - 1]), + n = bstr.length, + u8arr = new Uint8Array(n); + while (n--) { + u8arr[n] = bstr.charCodeAt(n); + } + return new File([u8arr], filename, {type: mime}); + } + + let file = dataURLtoFile(uri.value, `${itemInfo.value.documentNumber}.pdf`) + + await useFiles().uploadFiles(fileData, [file]) +} + +const regenerateMissingPdf = async () => { + guard.value = false + const showPath = `/createDocument/show/${route.params.id}` + + try { + const document = await useEntities("createddocuments").selectSingle(route.params.id, "*,files(*)") + + if (document?.state === "Entwurf" || document?.type === "serialInvoices") { + toast.add({ title: "PDF kann nur für fertiggestellte Belege nacherzeugt werden", color: "error" }) + } else if ((document?.files || []).length > 0) { + toast.add({ title: "Am Beleg ist bereits ein Dokument angehängt", color: "warning" }) + } else { + // Vertrags- und Mandats-Watcher überschreiben beim Laden die Zahlungsdaten, für die PDF gilt der gespeicherte Stand + const restoreStoredPaymentData = () => { + itemInfo.value.payment_type = document.payment_type + itemInfo.value.outgoingsepamandate = normalizeEntityId(document.outgoingsepamandate) + } + await nextTick() + restoreStoredPaymentData() + await nextTick() + restoreStoredPaymentData() + + await uploadGeneratedDocument() + toast.add({ title: "PDF nacherzeugt", color: "success" }) + } + } catch (error) { + console.error(error) + toast.add({ title: "PDF konnte nicht nacherzeugt werden", description: error?.data?.error || error?.message, color: "error" }) + } + + await router.replace(showPath) } const getTextTemplateByType = (type, pos) => { diff --git a/frontend/pages/createDocument/show/[id].vue b/frontend/pages/createDocument/show/[id].vue index 5f6af822..338b5bf3 100644 --- a/frontend/pages/createDocument/show/[id].vue +++ b/frontend/pages/createDocument/show/[id].vue @@ -110,10 +110,18 @@ const setupPage = async () => { links.value = createddocuments.filter(i => i.createddocument?.id === itemInfo.value.id) } - linkedDocument.value = await useFiles().selectDocument(itemInfo.value.files[0].id) + if (itemInfo.value.files?.length > 0) { + linkedDocument.value = await useFiles().selectDocument(itemInfo.value.files[0].id) + } } } +const canRegeneratePdf = computed(() => itemInfo.value.id + && itemInfo.value.state !== 'Entwurf' + && itemInfo.value.type !== 'serialInvoices' + && Array.isArray(itemInfo.value.files) + && itemInfo.value.files.length === 0) + setupPage() const getStatementLike = (allocation) => allocation?.bankstatement || (typeof allocation?.bs_id === "object" ? allocation.bs_id : null) @@ -282,6 +290,12 @@ const togglePortalRelease = async () => { :loading="costCentresLoading" @click="openCostCentres" >Kostenstellen bearbeiten + PDF nacherzeugen