From 1711f975bbca4a5eb2d4eda3f3ff88cc4b381faa Mon Sep 17 00:00:00 2001 From: florianfederspiel Date: Wed, 15 Jul 2026 10:15:11 +0200 Subject: [PATCH] =?UTF-8?q?KI-AGENT:=20Dropdown=20zum=20Einf=C3=BCgen=20vo?= =?UTF-8?q?n=20Dokumentpositionen=20erg=C3=A4nzt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/pages/createDocument/edit/[[id]].vue | 159 ++++++++++-------- 1 file changed, 89 insertions(+), 70 deletions(-) diff --git a/frontend/pages/createDocument/edit/[[id]].vue b/frontend/pages/createDocument/edit/[[id]].vue index d85b54a..767ab24 100644 --- a/frontend/pages/createDocument/edit/[[id]].vue +++ b/frontend/pages/createDocument/edit/[[id]].vue @@ -826,21 +826,18 @@ const getRowAmountUndiscounted = (row) => { return String(Number(Number(row.quantity) * Number(row.price)).toFixed(2)).replace('.', ',') } -const addPosition = (mode) => { - - let lastId = 0 - itemInfo.value.rows.forEach(row => { - if (row.id > lastId) lastId = row.id - }) - - let taxPercentage = 19 - - if (['13b UStG', '19 UStG', '12.3 UStG'].includes(itemInfo.value.taxType)) { - taxPercentage = 0 - } +const positionAddOptions = [ + { mode: 'service', label: 'Leistung', icon: 'i-heroicons-wrench-screwdriver' }, + { mode: 'normal', label: 'Artikel', icon: 'i-heroicons-cube' }, + { mode: 'free', label: 'Freie Position', icon: 'i-heroicons-pencil-square' }, + { mode: 'pagebreak', label: 'Seitenumbruch', icon: 'i-heroicons-document-minus' }, + { mode: 'title', label: 'Titel', icon: 'i-heroicons-bars-3-bottom-left' }, + { mode: 'text', label: 'Text', icon: 'i-heroicons-document-text' } +] +const createPositionRow = (mode, taxPercentage) => { if (mode === 'free') { - let rowData = { + const rowData = { id: uuidv4(), mode: "free", text: "", @@ -855,10 +852,11 @@ const addPosition = (mode) => { linkedEntitys: [] } - itemInfo.value.rows.push({...rowData, ...auth.activeTenantData.extraModules.includes("agriculture") ? {agriculture: {}} : {}}) + return {...rowData, ...auth.activeTenantData.extraModules.includes("agriculture") ? {agriculture: {}} : {}} + } - } else if (mode === 'normal') { - itemInfo.value.rows.push({ + if (mode === 'normal') { + return { id: uuidv4(), mode: "normal", quantity: 1, @@ -869,9 +867,11 @@ const addPosition = (mode) => { unit: 1, costCentre: itemInfo.value.costcentre, linkedEntitys: [] - }) - } else if (mode === 'service') { - let rowData = { + } + } + + if (mode === 'service') { + const rowData = { id: uuidv4(), mode: "service", quantity: 1, @@ -884,26 +884,63 @@ const addPosition = (mode) => { linkedEntitys: [] } - //Push Agriculture Holder only if Module is activated - itemInfo.value.rows.push({...rowData, ...auth.activeTenantData.extraModules.includes("agriculture") ? {agriculture: {}} : {}}) - } else if (mode === "pagebreak") { - itemInfo.value.rows.push({ + return {...rowData, ...auth.activeTenantData.extraModules.includes("agriculture") ? {agriculture: {}} : {}} + } + + if (mode === "pagebreak") { + return { id: uuidv4(), mode: "pagebreak", linkedEntitys: [] - }) - } else if (mode === "title") { - itemInfo.value.rows.push({ + } + } + + if (mode === "title") { + return { id: uuidv4(), mode: "title", linkedEntitys: [] - }) - } else if (mode === "text") { - itemInfo.value.rows.push({ + } + } + + if (mode === "text") { + return { id: uuidv4(), mode: "text", linkedEntitys: [] - }) + } + } + + return null +} + +const getPositionAddMenuItems = (row) => [ + positionAddOptions.map(option => ({ + ...option, + onSelect: () => addPosition(option.mode, row?.id) + })) +] + +const getFullWidthPositionColspan = () => deliveryNoteLikeDocumentTypes.includes(itemInfo.value.type) ? 5 : 8 + +const getTitlePositionColspan = () => deliveryNoteLikeDocumentTypes.includes(itemInfo.value.type) ? 4 : 7 + +const addPosition = (mode, afterRowId = null) => { + let taxPercentage = 19 + + if (['13b UStG', '19 UStG', '12.3 UStG'].includes(itemInfo.value.taxType)) { + taxPercentage = 0 + } + + const newRow = createPositionRow(mode, taxPercentage) + if (!newRow) return + + const insertAfterIndex = afterRowId ? itemInfo.value.rows.findIndex(row => row.id === afterRowId) : -1 + + if (insertAfterIndex >= 0) { + itemInfo.value.rows.splice(insertAfterIndex + 1, 0, newRow) + } else { + itemInfo.value.rows.push(newRow) } setPosNumbers() @@ -2797,6 +2834,8 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = { Rabatt--> Gesamt + +