From 11a242d70d68ab9a511a741c8e14775b435e98fe Mon Sep 17 00:00:00 2001 From: florianfederspiel Date: Sun, 22 Mar 2026 17:43:41 +0100 Subject: [PATCH] 4. Zwischenstand --- frontend/components/MainNav.vue | 99 +++--- frontend/components/displayBWASummary.vue | 221 +++++++++++++ frontend/pages/accounting/bwa.vue | 273 +++++++++------- frontend/pages/accounting/tax.vue | 296 +++++++++--------- frontend/pages/createDocument/edit/[[id]].vue | 17 +- frontend/pages/createDocument/index.vue | 10 +- frontend/pages/index.client.vue | 228 +++++++------- 7 files changed, 724 insertions(+), 420 deletions(-) create mode 100644 frontend/components/displayBWASummary.vue diff --git a/frontend/components/MainNav.vue b/frontend/components/MainNav.vue index bfd5f6e..d8a8053 100644 --- a/frontend/components/MainNav.vue +++ b/frontend/components/MainNav.vue @@ -136,30 +136,37 @@ const links = computed(() => { to: "/incomingInvoices", icon: "i-heroicons-document-text", } : null, - (featureEnabled("createDocument") || featureEnabled("incomingInvoices")) ? { - label: "USt-Auswertung", - to: "/accounting/tax", - icon: "i-heroicons-calculator", - } : null, - (featureEnabled("createDocument") || featureEnabled("incomingInvoices") || featureEnabled("accounts") || featureEnabled("ownaccounts")) ? { - label: "BWA", - to: "/accounting/bwa", - icon: "i-heroicons-chart-bar-square", - } : null, - featureEnabled("costcentres") ? { - label: "Kostenstellen", - to: "/standardEntity/costcentres", - icon: "i-heroicons-document-currency-euro" - } : null, - featureEnabled("accounts") ? { - label: "Buchungskonten", - to: "/accounts", - icon: "i-heroicons-document-text", - } : null, - featureEnabled("ownaccounts") ? { - label: "zusätzliche Buchungskonten", - to: "/standardEntity/ownaccounts", - icon: "i-heroicons-document-text" + ((featureEnabled("createDocument") || featureEnabled("incomingInvoices")) || featureEnabled("accounts") || featureEnabled("ownaccounts") || featureEnabled("costcentres")) ? { + label: "Auswertungen", + icon: "i-heroicons-chart-pie", + defaultOpen: false, + children: visibleItems([ + (featureEnabled("createDocument") || featureEnabled("incomingInvoices")) ? { + label: "USt", + to: "/accounting/tax", + icon: "i-heroicons-calculator", + } : null, + (featureEnabled("createDocument") || featureEnabled("incomingInvoices") || featureEnabled("accounts") || featureEnabled("ownaccounts")) ? { + label: "BWA", + to: "/accounting/bwa", + icon: "i-heroicons-chart-bar-square", + } : null, + featureEnabled("costcentres") ? { + label: "Kostenstellen", + to: "/standardEntity/costcentres", + icon: "i-heroicons-document-currency-euro" + } : null, + featureEnabled("accounts") ? { + label: "Buchungskonten", + to: "/accounts", + icon: "i-heroicons-document-text", + } : null, + featureEnabled("ownaccounts") ? { + label: "Zusätzliche Buchungskonten", + to: "/standardEntity/ownaccounts", + icon: "i-heroicons-document-text" + } : null, + ]) } : null, featureEnabled("banking") ? { label: "Bank", @@ -401,31 +408,31 @@ const links = computed(() => { ]) }) +const mapNavItem = (item, valuePrefix = "item") => { + const children = Array.isArray(item.children) + ? item.children + .filter(Boolean) + .map((child, index) => mapNavItem(child, `${valuePrefix}-${index}`)) + : undefined + + const active = item.active || isRouteActive(item.to) || Boolean(children?.some(child => child.active)) + + return { + ...item, + children, + value: item.id || item.label || valuePrefix, + defaultOpen: item.defaultOpen || active, + active, + tooltip: true, + popover: true, + trailingIcon: children?.length ? undefined : '' + } +} + const navItems = computed(() => links.value .filter(Boolean) - .map((item, index) => { - const children = Array.isArray(item.children) - ? item.children.map((child, childIndex) => ({ - ...child, - value: child.id || child.label || `${index}-${childIndex}`, - active: isRouteActive(child.to) - })) - : undefined - - const active = item.active || isRouteActive(item.to) || Boolean(children?.some(child => child.active)) - - return { - ...item, - children, - value: item.id || item.label || String(index), - defaultOpen: item.defaultOpen || active, - active, - tooltip: true, - popover: true, - trailingIcon: children?.length ? undefined : '' - } - }) + .map((item, index) => mapNavItem(item, String(index))) ) diff --git a/frontend/components/displayBWASummary.vue b/frontend/components/displayBWASummary.vue new file mode 100644 index 0000000..6d28e8f --- /dev/null +++ b/frontend/components/displayBWASummary.vue @@ -0,0 +1,221 @@ + + + + + diff --git a/frontend/pages/accounting/bwa.vue b/frontend/pages/accounting/bwa.vue index e5637d4..e7f12c4 100644 --- a/frontend/pages/accounting/bwa.vue +++ b/frontend/pages/accounting/bwa.vue @@ -34,21 +34,21 @@ const monthItems = [ ] const accountColumns = [ - { accessorKey: "number", header: "Nummer" }, - { accessorKey: "label", header: "Konto" }, - { accessorKey: "bookings", header: "Buchungen" }, + { accessorKey: "gross", header: "Brutto" }, { accessorKey: "net", header: "Netto" }, { accessorKey: "tax", header: "Steuer" }, - { accessorKey: "gross", header: "Brutto" } + { accessorKey: "number", header: "Nummer" }, + { accessorKey: "label", header: "Konto" }, + { accessorKey: "bookings", header: "Buchungen" } ] const ownAccountColumns = [ + { accessorKey: "balance", header: "Saldo" }, + { accessorKey: "expenses", header: "Ausgaben" }, + { accessorKey: "income", header: "Einnahmen" }, { accessorKey: "number", header: "Nummer" }, { accessorKey: "label", header: "Konto" }, - { accessorKey: "bookings", header: "Buchungen" }, - { accessorKey: "income", header: "Einnahmen" }, - { accessorKey: "expenses", header: "Ausgaben" }, - { accessorKey: "balance", header: "Saldo" } + { accessorKey: "bookings", header: "Buchungen" } ] const isRelevantOutputDocument = (doc: any) => { @@ -148,18 +148,36 @@ const filteredStatementAllocations = computed(() => { return statementAllocations.value.filter((allocation) => matchesSelectedPeriod(getStatementDate(allocation))) }) +const filteredAccountStatementAllocations = computed(() => { + return filteredStatementAllocations.value.filter((allocation) => allocation.account !== null && allocation.account !== undefined) +}) + const incomeTotal = computed(() => { return Number(filteredDocuments.value.reduce((sum, doc) => sum + computeDocumentNet(doc), 0).toFixed(2)) }) const expenseNetTotal = computed(() => { - return Number(filteredIncomingInvoices.value.reduce((sum, invoice) => { + const invoiceExpenses = filteredIncomingInvoices.value.reduce((sum, invoice) => { return sum + (invoice.accounts || []).reduce((accountSum: number, account: any) => accountSum + Number(account.amountNet || 0), 0) - }, 0).toFixed(2)) + }, 0) + + const directAccountExpenses = filteredAccountStatementAllocations.value.reduce((sum, allocation) => { + const amount = Number(allocation.amount || 0) + return amount < 0 ? sum + Math.abs(amount) : sum + }, 0) + + return Number((invoiceExpenses + directAccountExpenses).toFixed(2)) }) const expenseGrossTotal = computed(() => { - return Number(filteredIncomingInvoices.value.reduce((sum, invoice) => sum + computeIncomingInvoiceGross(invoice), 0).toFixed(2)) + const invoiceExpenses = filteredIncomingInvoices.value.reduce((sum, invoice) => sum + computeIncomingInvoiceGross(invoice), 0) + + const directAccountExpenses = filteredAccountStatementAllocations.value.reduce((sum, allocation) => { + const amount = Number(allocation.amount || 0) + return amount < 0 ? sum + Math.abs(amount) : sum + }, 0) + + return Number((invoiceExpenses + directAccountExpenses).toFixed(2)) }) const taxSummary = computed(() => { @@ -201,14 +219,42 @@ const operatingResult = computed(() => { return Number((incomeTotal.value - expenseNetTotal.value).toFixed(2)) }) +const incomeDocumentCount = computed(() => filteredDocuments.value.length) +const expenseDocumentCount = computed(() => { + return filteredIncomingInvoices.value.length + filteredAccountStatementAllocations.value.length +}) + const accountRows = computed(() => { return accounts.value .map((account) => { - const bookings = filteredIncomingInvoices.value.flatMap((invoice) => { + const invoiceBookings = filteredIncomingInvoices.value.flatMap((invoice) => { return (invoice.accounts || []) .filter((invoiceAccount: any) => sameId(invoiceAccount.account?.id || invoiceAccount.account, account.id)) + .map((invoiceAccount: any) => ({ + type: "incominginvoice", + amountNet: Number(invoiceAccount.amountNet || 0), + amountTax: Number(invoiceAccount.amountTax || 0), + amountGross: Number.isFinite(Number(invoiceAccount.amountGross)) + ? Number(invoiceAccount.amountGross) + : Number(invoiceAccount.amountNet || 0) + Number(invoiceAccount.amountTax || 0) + })) }) + const directBookings = filteredAccountStatementAllocations.value + .filter((allocation) => sameId(allocation.account?.id || allocation.account, account.id)) + .map((allocation) => { + const amount = Number(allocation.amount || 0) + + return { + type: "statementallocation", + amountNet: amount, + amountTax: 0, + amountGross: amount + } + }) + + const bookings = [...invoiceBookings, ...directBookings] + if (bookings.length === 0) { return null } @@ -231,7 +277,7 @@ const accountRows = computed(() => { } }) .filter(Boolean) - .sort((left: any, right: any) => Number(right.gross) - Number(left.gross)) + .sort((left: any, right: any) => Math.abs(Number(right.gross)) - Math.abs(Number(left.gross))) }) const ownAccountRows = computed(() => { @@ -315,16 +361,7 @@ onMounted(setupPage)