Added Abschreibungen
This commit is contained in:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user