Added Abschreibungen

This commit is contained in:
2026-03-25 17:13:59 +01:00
parent f6c9875320
commit 42e0d7b35e
16 changed files with 13054 additions and 55 deletions

View File

@@ -4,6 +4,15 @@ import {
getCreatedDocumentTaxBreakdown,
getIncomingInvoiceTaxBreakdown
} from "~/composables/useTaxEvaluation"
import {
getIncomingInvoiceDepreciationRows,
getIncomingInvoiceImmediateExpenseGross,
getIncomingInvoiceImmediateExpenseNet,
isDepreciationBookingMode,
normalizeIncomingInvoiceAccount,
getStatementAllocationDepreciationRow,
getStatementAllocationImmediateExpenseAmount
} from "~/composables/useDepreciation"
const router = useRouter()
@@ -51,6 +60,14 @@ const ownAccountColumns = [
{ accessorKey: "bookings", header: "Buchungen" }
]
const depreciationColumns = [
{ accessorKey: "label", header: "Abschreibung" },
{ accessorKey: "groupLabel", header: "Gruppe" },
{ accessorKey: "modeLabel", header: "Art" },
{ accessorKey: "amount", header: "Betrag" },
{ accessorKey: "bookings", header: "Positionen" }
]
const isRelevantOutputDocument = (doc: any) => {
return doc?.state === "Gebucht" && ["invoices", "advanceInvoices", "cancellationInvoices"].includes(doc?.type)
}
@@ -97,16 +114,6 @@ const computeDocumentNet = (doc: any) => {
}, 0).toFixed(2))
}
const computeIncomingInvoiceGross = (invoice: any) => {
return Number((invoice?.accounts || []).reduce((sum: number, account: any) => {
const amountNet = Number(account?.amountNet || 0)
const amountTax = Number(account?.amountTax || 0)
const amountGross = Number(account?.amountGross)
return sum + (Number.isFinite(amountGross) ? amountGross : amountNet + amountTax)
}, 0).toFixed(2))
}
const yearItems = computed(() => {
const years = new Set<string>([String(dayjs().year())])
@@ -152,32 +159,46 @@ const filteredAccountStatementAllocations = computed(() => {
return filteredStatementAllocations.value.filter((allocation) => allocation.account !== null && allocation.account !== undefined)
})
const selectedPeriodBounds = computed(() => {
const start = selectedMonth.value === "all"
? dayjs(`${selectedYear.value}-01-01`).startOf("day")
: dayjs(`${selectedYear.value}-${String(selectedMonth.value).padStart(2, "0")}-01`).startOf("month")
const end = selectedMonth.value === "all"
? dayjs(`${selectedYear.value}-12-31`).endOf("day")
: start.endOf("month")
return { start, end }
})
const incomeTotal = computed(() => {
return Number(filteredDocuments.value.reduce((sum, doc) => sum + computeDocumentNet(doc), 0).toFixed(2))
})
const expenseNetTotal = computed(() => {
const invoiceExpenses = filteredIncomingInvoices.value.reduce((sum, invoice) => {
return sum + (invoice.accounts || []).reduce((accountSum: number, account: any) => accountSum + Number(account.amountNet || 0), 0)
return sum + getIncomingInvoiceImmediateExpenseNet(invoice)
}, 0)
const directAccountExpenses = filteredAccountStatementAllocations.value.reduce((sum, allocation) => {
const amount = Number(allocation.amount || 0)
return amount < 0 ? sum + Math.abs(amount) : sum
return sum + getStatementAllocationImmediateExpenseAmount(allocation)
}, 0)
return Number((invoiceExpenses + directAccountExpenses).toFixed(2))
const depreciations = depreciationTotal.value
return Number((invoiceExpenses + directAccountExpenses + depreciations).toFixed(2))
})
const expenseGrossTotal = computed(() => {
const invoiceExpenses = filteredIncomingInvoices.value.reduce((sum, invoice) => sum + computeIncomingInvoiceGross(invoice), 0)
const invoiceExpenses = filteredIncomingInvoices.value.reduce((sum, invoice) => sum + getIncomingInvoiceImmediateExpenseGross(invoice), 0)
const directAccountExpenses = filteredAccountStatementAllocations.value.reduce((sum, allocation) => {
const amount = Number(allocation.amount || 0)
return amount < 0 ? sum + Math.abs(amount) : sum
return sum + getStatementAllocationImmediateExpenseAmount(allocation)
}, 0)
return Number((invoiceExpenses + directAccountExpenses).toFixed(2))
const depreciations = depreciationTotal.value
return Number((invoiceExpenses + directAccountExpenses + depreciations).toFixed(2))
})
const taxSummary = computed(() => {
@@ -221,7 +242,42 @@ const operatingResult = computed(() => {
const incomeDocumentCount = computed(() => filteredDocuments.value.length)
const expenseDocumentCount = computed(() => {
return filteredIncomingInvoices.value.length + filteredAccountStatementAllocations.value.length
const directExpenseCount = filteredAccountStatementAllocations.value.filter((allocation) => getStatementAllocationImmediateExpenseAmount(allocation) > 0).length
return filteredIncomingInvoices.value.filter((invoice) => getIncomingInvoiceImmediateExpenseNet(invoice) > 0).length + directExpenseCount
})
const depreciationRows = computed(() => {
const invoiceRows = filteredIncomingInvoices.value.flatMap((invoice) => getIncomingInvoiceDepreciationRows(invoice, selectedPeriodBounds.value.start, selectedPeriodBounds.value.end))
const allocationRows = filteredStatementAllocations.value
.map((allocation) => getStatementAllocationDepreciationRow(allocation, selectedPeriodBounds.value.start, selectedPeriodBounds.value.end))
.filter(Boolean)
const grouped = new Map<string, any>()
;[...invoiceRows, ...allocationRows].forEach((row: any) => {
const key = row.group || `${row.mode}:${row.label}`
const current = grouped.get(key) || {
id: key,
label: row.group || row.label,
groupLabel: row.group || "-",
modeLabel: row.mode === "depreciation_bundle" ? "Sammelposten" : "Einzeln",
amount: 0,
bookings: 0
}
current.amount += Number(row.amount || 0)
current.bookings += 1
grouped.set(key, current)
})
return Array.from(grouped.values())
.map((row) => ({ ...row, amount: Number(row.amount.toFixed(2)) }))
.sort((left, right) => Number(right.amount) - Number(left.amount))
})
const depreciationTotal = computed(() => {
return Number(depreciationRows.value.reduce((sum, row) => sum + Number(row.amount || 0), 0).toFixed(2))
})
const accountRows = computed(() => {
@@ -229,6 +285,7 @@ const accountRows = computed(() => {
.map((account) => {
const invoiceBookings = filteredIncomingInvoices.value.flatMap((invoice) => {
return (invoice.accounts || [])
.filter((invoiceAccount: any) => !isDepreciationBookingMode(normalizeIncomingInvoiceAccount(invoiceAccount, invoice?.date).bookingMode))
.filter((invoiceAccount: any) => sameId(invoiceAccount.account?.id || invoiceAccount.account, account.id))
.map((invoiceAccount: any) => ({
type: "incominginvoice",
@@ -241,6 +298,7 @@ const accountRows = computed(() => {
})
const directBookings = filteredAccountStatementAllocations.value
.filter((allocation) => getStatementAllocationImmediateExpenseAmount(allocation) > 0)
.filter((allocation) => sameId(allocation.account?.id || allocation.account, account.id))
.map((allocation) => {
const amount = Number(allocation.amount || 0)
@@ -387,7 +445,7 @@ onMounted(setupPage)
</UFormField>
</div>
<div class="grid min-w-0 gap-4 md:grid-cols-2 xl:grid-cols-4">
<div class="grid min-w-0 gap-4 md:grid-cols-2 xl:grid-cols-5">
<UCard class="min-w-0">
<div class="text-sm text-gray-500 dark:text-gray-400">Einnahmen netto</div>
<div class="mt-2 text-2xl font-semibold">{{ useCurrency(incomeTotal) }}</div>
@@ -398,12 +456,20 @@ onMounted(setupPage)
<UCard class="min-w-0">
<div class="text-sm text-gray-500 dark:text-gray-400">Ausgaben netto</div>
<div class="mt-2 text-2xl font-semibold">{{ useCurrency(expenseNetTotal) }}</div>
<div class="mt-2 text-2xl font-semibold">{{ useCurrency(expenseNetTotal) }}</div>
<div class="mt-2 text-sm text-gray-500 dark:text-gray-400">
Brutto: {{ useCurrency(expenseGrossTotal) }}
</div>
</UCard>
<UCard class="min-w-0">
<div class="text-sm text-gray-500 dark:text-gray-400">Abschreibungen</div>
<div class="mt-2 text-2xl font-semibold text-amber-600 dark:text-amber-400">{{ useCurrency(depreciationTotal) }}</div>
<div class="mt-2 text-sm text-gray-500 dark:text-gray-400">
{{ depreciationRows.length }} periodisierte Buchungen
</div>
</UCard>
<UCard class="min-w-0">
<div class="text-sm text-gray-500 dark:text-gray-400">Einnahmen Belege</div>
<div class="mt-2 text-2xl font-semibold">{{ incomeDocumentCount }}</div>
@@ -503,10 +569,10 @@ onMounted(setupPage)
</UCard>
</div>
<div class="grid min-w-0 gap-4 xl:grid-cols-2">
<UCard class="min-w-0">
<template #header>
<div class="flex items-center justify-between gap-3">
<div class="grid min-w-0 gap-4 xl:grid-cols-2">
<UCard class="min-w-0">
<template #header>
<div class="flex items-center justify-between gap-3">
<span class="font-semibold">Buchungskonten</span>
<UBadge color="neutral" variant="soft">{{ accountRows.length }}</UBadge>
</div>
@@ -594,7 +660,26 @@ onMounted(setupPage)
</template>
</UTable>
</div>
</UCard>
</div>
<UCard class="min-w-0" v-if="depreciationRows.length > 0">
<template #header>
<div class="flex items-center justify-between gap-3">
<span class="font-semibold">Abschreibungen</span>
<UBadge color="warning" variant="soft">{{ depreciationRows.length }}</UBadge>
</div>
</template>
<UTable
:data="depreciationRows"
:columns="normalizeTableColumns(depreciationColumns)"
:loading="loading"
>
<template #amount-cell="{ row }">
<div class="text-right text-amber-600 dark:text-amber-400 tabular-nums">{{ useCurrency(row.original.amount) }}</div>
</template>
</UTable>
</UCard>
</div>
</UDashboardPanelContent>
</template>