From ac00d2187ea73cb7c484dafa30a7766ec890195c Mon Sep 17 00:00:00 2001 From: flfeders Date: Wed, 7 Oct 2026 18:50:38 +0200 Subject: [PATCH] feat(accounting): edit cost centres from finalized outgoing documents --- frontend/pages/createDocument/show/[id].vue | 99 +++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/frontend/pages/createDocument/show/[id].vue b/frontend/pages/createDocument/show/[id].vue index d7ed17b9..5f6af822 100644 --- a/frontend/pages/createDocument/show/[id].vue +++ b/frontend/pages/createDocument/show/[id].vue @@ -22,6 +22,69 @@ const linkedDocument =ref({}) const links = ref([]) const portalReleaseLoading = ref(false) const bankBookingModalOpen = ref(false) +const costCentresOpen = ref(false) +const costCentresLoading = ref(false) +const costCentresSaving = ref(false) +const costCentres = ref([]) +const costCentreDraft = ref({ costcentre: null, rows: [] }) +const costCentreId = (value) => value?.id || value || null +const costCentreLabel = (id) => { + const centre = costCentres.value.find(item => item.id === id) + return centre ? [centre.number, centre.name].filter(Boolean).join(" - ") : (id ? "Bisherige Kostenstelle" : "Keine Kostenstelle") +} + +const openCostCentres = async () => { + costCentresLoading.value = true + try { + costCentres.value = await useEntities("costcentres").select("*") + costCentreDraft.value = { + costcentre: costCentreId(itemInfo.value.costcentre), + rows: (itemInfo.value.rows || []) + .filter(row => row?.id != null && row.id !== "" && !["title", "subtitle", "text", "pagebreak"].includes(row.mode)) + .map((row, index) => ({ + rowId: String(row.id), + label: `${row.pos || index + 1}. ${row.text || row.name || row.descriptionText || "Position"}`, + costcentre: costCentreId(row.costCentre ?? row.costcentre), + })), + } + costCentresOpen.value = true + } catch (error) { + toast.add({ title: "Kostenstellen konnten nicht geladen werden", color: "error" }) + } finally { + costCentresLoading.value = false + } +} + +const saveCostCentres = async () => { + if (costCentresSaving.value) return + costCentresSaving.value = true + try { + const originalRows = new Map((itemInfo.value.rows || []).map(row => [String(row.id), row])) + const body = { + rowCostCentres: costCentreDraft.value.rows + .filter(row => row.costcentre !== costCentreId(originalRows.get(row.rowId)?.costCentre ?? originalRows.get(row.rowId)?.costcentre)) + .map(({ rowId, costcentre }) => ({ rowId, costcentre })), + } + if (costCentreDraft.value.costcentre !== costCentreId(itemInfo.value.costcentre)) { + body.costcentre = costCentreDraft.value.costcentre + } + if (body.rowCostCentres.length || Object.hasOwn(body, "costcentre")) { + const { document } = await useNuxtApp().$api(`/api/functions/outgoing-documents/${itemInfo.value.id}/cost-centres`, { + method: "PUT", + body, + }) + itemInfo.value.costcentre = document.costcentre + itemInfo.value.rows = document.rows + toast.add({ title: "Kostenstellen gespeichert", color: "success" }) + } + costCentresOpen.value = false + } catch (error) { + toast.add({ title: "Kostenstellen konnten nicht gespeichert werden", description: error?.data?.error || "Bitte versuche es erneut.", color: "error" }) + } finally { + costCentresSaving.value = false + } +} + const portalEligibleTypes = ["invoices", "advanceInvoices", "cancellationInvoices"] const loadStatementAllocations = async () => { @@ -212,6 +275,13 @@ const togglePortalRelease = async () => { > Bearbeiten + Kostenstellen bearbeiten