601 lines
21 KiB
Vue
601 lines
21 KiB
Vue
<script setup lang="ts">
|
|
import dayjs from "dayjs"
|
|
import {
|
|
getCreatedDocumentTaxBreakdown,
|
|
getIncomingInvoiceTaxBreakdown
|
|
} from "~/composables/useTaxEvaluation"
|
|
|
|
const router = useRouter()
|
|
|
|
const loading = ref(true)
|
|
const createdDocuments = ref<any[]>([])
|
|
const incomingInvoices = ref<any[]>([])
|
|
const accounts = ref<any[]>([])
|
|
const ownAccounts = ref<any[]>([])
|
|
const statementAllocations = ref<any[]>([])
|
|
|
|
const selectedYear = ref(String(dayjs().year()))
|
|
const selectedMonth = ref("all")
|
|
|
|
const monthItems = [
|
|
{ label: "Ganzes Jahr", value: "all" },
|
|
{ label: "Januar", value: "1" },
|
|
{ label: "Februar", value: "2" },
|
|
{ label: "Maerz", value: "3" },
|
|
{ label: "April", value: "4" },
|
|
{ label: "Mai", value: "5" },
|
|
{ label: "Juni", value: "6" },
|
|
{ label: "Juli", value: "7" },
|
|
{ label: "August", value: "8" },
|
|
{ label: "September", value: "9" },
|
|
{ label: "Oktober", value: "10" },
|
|
{ label: "November", value: "11" },
|
|
{ label: "Dezember", value: "12" }
|
|
]
|
|
|
|
const accountColumns = [
|
|
{ accessorKey: "gross", header: "Brutto" },
|
|
{ accessorKey: "net", header: "Netto" },
|
|
{ accessorKey: "tax", header: "Steuer" },
|
|
{ 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" }
|
|
]
|
|
|
|
const isRelevantOutputDocument = (doc: any) => {
|
|
return doc?.state === "Gebucht" && ["invoices", "advanceInvoices", "cancellationInvoices"].includes(doc?.type)
|
|
}
|
|
|
|
const isRelevantInputInvoice = (invoice: any) => {
|
|
return invoice?.state === "Gebucht" && !!invoice?.date
|
|
}
|
|
|
|
const sameId = (left: any, right: any) => String(left ?? "") === String(right ?? "")
|
|
|
|
const getStatementDate = (allocation: any) => {
|
|
return allocation?.bankstatement?.date || allocation?.bankstatement?.valueDate || allocation?.date || allocation?.created_at || null
|
|
}
|
|
|
|
const matchesSelectedPeriod = (dateValue: any) => {
|
|
const parsed = dayjs(dateValue)
|
|
|
|
if (!parsed.isValid()) {
|
|
return false
|
|
}
|
|
|
|
if (String(parsed.year()) !== selectedYear.value) {
|
|
return false
|
|
}
|
|
|
|
if (selectedMonth.value !== "all" && parsed.month() + 1 !== Number(selectedMonth.value)) {
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
const computeDocumentNet = (doc: any) => {
|
|
return Number((doc?.rows || []).reduce((sum: number, row: any) => {
|
|
if (!row || ["pagebreak", "title", "text"].includes(row.mode)) {
|
|
return sum
|
|
}
|
|
|
|
const quantity = Number(row.quantity || 0)
|
|
const price = Number(row.price || 0)
|
|
const discountPercent = Number(row.discountPercent || 0)
|
|
|
|
return sum + (quantity * price * (1 - discountPercent / 100))
|
|
}, 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())])
|
|
|
|
createdDocuments.value.forEach((doc) => {
|
|
const parsed = dayjs(doc.documentDate)
|
|
if (parsed.isValid()) {
|
|
years.add(String(parsed.year()))
|
|
}
|
|
})
|
|
|
|
incomingInvoices.value.forEach((invoice) => {
|
|
const parsed = dayjs(invoice.date)
|
|
if (parsed.isValid()) {
|
|
years.add(String(parsed.year()))
|
|
}
|
|
})
|
|
|
|
statementAllocations.value.forEach((allocation) => {
|
|
const parsed = dayjs(getStatementDate(allocation))
|
|
if (parsed.isValid()) {
|
|
years.add(String(parsed.year()))
|
|
}
|
|
})
|
|
|
|
return Array.from(years)
|
|
.sort((a, b) => Number(b) - Number(a))
|
|
.map((year) => ({ label: year, value: year }))
|
|
})
|
|
|
|
const filteredDocuments = computed(() => {
|
|
return createdDocuments.value.filter((doc) => matchesSelectedPeriod(doc.documentDate))
|
|
})
|
|
|
|
const filteredIncomingInvoices = computed(() => {
|
|
return incomingInvoices.value.filter((invoice) => matchesSelectedPeriod(invoice.date))
|
|
})
|
|
|
|
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(() => {
|
|
const invoiceExpenses = filteredIncomingInvoices.value.reduce((sum, invoice) => {
|
|
return sum + (invoice.accounts || []).reduce((accountSum: number, account: any) => accountSum + Number(account.amountNet || 0), 0)
|
|
}, 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(() => {
|
|
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(() => {
|
|
const output = filteredDocuments.value.reduce((sum, doc) => {
|
|
const breakdown = getCreatedDocumentTaxBreakdown(doc)
|
|
return {
|
|
net19: sum.net19 + breakdown.net19,
|
|
tax19: sum.tax19 + breakdown.tax19,
|
|
net7: sum.net7 + breakdown.net7,
|
|
tax7: sum.tax7 + breakdown.tax7,
|
|
net0: sum.net0 + breakdown.net0
|
|
}
|
|
}, { net19: 0, tax19: 0, net7: 0, tax7: 0, net0: 0 })
|
|
|
|
const input = filteredIncomingInvoices.value.reduce((sum, invoice) => {
|
|
const breakdown = getIncomingInvoiceTaxBreakdown(invoice)
|
|
return {
|
|
net19: sum.net19 + breakdown.net19,
|
|
tax19: sum.tax19 + breakdown.tax19,
|
|
net7: sum.net7 + breakdown.net7,
|
|
tax7: sum.tax7 + breakdown.tax7,
|
|
net0: sum.net0 + breakdown.net0
|
|
}
|
|
}, { net19: 0, tax19: 0, net7: 0, tax7: 0, net0: 0 })
|
|
|
|
const outputTax = Number((output.tax19 + output.tax7).toFixed(2))
|
|
const inputTax = Number((input.tax19 + input.tax7).toFixed(2))
|
|
|
|
return {
|
|
output,
|
|
input,
|
|
outputTax,
|
|
inputTax,
|
|
balance: Number((outputTax - inputTax).toFixed(2))
|
|
}
|
|
})
|
|
|
|
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 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
|
|
}
|
|
|
|
const net = bookings.reduce((sum, booking: any) => sum + Number(booking.amountNet || 0), 0)
|
|
const tax = bookings.reduce((sum, booking: any) => sum + Number(booking.amountTax || 0), 0)
|
|
const gross = bookings.reduce((sum, booking: any) => {
|
|
const amountGross = Number(booking.amountGross)
|
|
return sum + (Number.isFinite(amountGross) ? amountGross : Number(booking.amountNet || 0) + Number(booking.amountTax || 0))
|
|
}, 0)
|
|
|
|
return {
|
|
id: account.id,
|
|
number: account.number || "-",
|
|
label: account.label || account.name || "-",
|
|
bookings: bookings.length,
|
|
net: Number(net.toFixed(2)),
|
|
tax: Number(tax.toFixed(2)),
|
|
gross: Number(gross.toFixed(2))
|
|
}
|
|
})
|
|
.filter(Boolean)
|
|
.sort((left: any, right: any) => Math.abs(Number(right.gross)) - Math.abs(Number(left.gross)))
|
|
})
|
|
|
|
const ownAccountRows = computed(() => {
|
|
return ownAccounts.value
|
|
.map((account) => {
|
|
const bookings = filteredStatementAllocations.value.filter((allocation) => sameId(allocation.ownaccount?.id || allocation.ownaccount, account.id))
|
|
|
|
if (bookings.length === 0) {
|
|
return null
|
|
}
|
|
|
|
const income = bookings.reduce((sum, booking) => {
|
|
const amount = Number(booking.amount || 0)
|
|
return amount > 0 ? sum + amount : sum
|
|
}, 0)
|
|
|
|
const expenses = bookings.reduce((sum, booking) => {
|
|
const amount = Number(booking.amount || 0)
|
|
return amount < 0 ? sum + Math.abs(amount) : sum
|
|
}, 0)
|
|
|
|
const balance = bookings.reduce((sum, booking) => sum + Number(booking.amount || 0), 0)
|
|
|
|
return {
|
|
id: account.id,
|
|
number: account.number || "-",
|
|
label: account.name || account.label || "-",
|
|
bookings: bookings.length,
|
|
income: Number(income.toFixed(2)),
|
|
expenses: Number(expenses.toFixed(2)),
|
|
balance: Number(balance.toFixed(2))
|
|
}
|
|
})
|
|
.filter(Boolean)
|
|
.sort((left: any, right: any) => Math.abs(Number(right.balance)) - Math.abs(Number(left.balance)))
|
|
})
|
|
|
|
const setupPage = async () => {
|
|
loading.value = true
|
|
|
|
try {
|
|
const [docs, invoices, accountItems, ownAccountItems, allocationItems] = await Promise.all([
|
|
useEntities("createddocuments").select(),
|
|
useEntities("incominginvoices").select("*, vendor(*)"),
|
|
useEntities("accounts").selectSpecial(),
|
|
useEntities("ownaccounts").select(),
|
|
useEntities("statementallocations").select("*, bankstatement(*), createddocument(*), incominginvoice(*)")
|
|
])
|
|
|
|
createdDocuments.value = (docs || []).filter(isRelevantOutputDocument)
|
|
incomingInvoices.value = (invoices || []).filter(isRelevantInputInvoice)
|
|
accounts.value = accountItems || []
|
|
ownAccounts.value = ownAccountItems || []
|
|
statementAllocations.value = allocationItems || []
|
|
|
|
const firstYear = yearItems.value[0]?.value
|
|
if (firstYear && !yearItems.value.some((item) => item.value === selectedYear.value)) {
|
|
selectedYear.value = firstYear
|
|
}
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
const openAccount = (rowLike: any) => {
|
|
const row = rowLike?.original || rowLike
|
|
if (row?.id) {
|
|
router.push(`/accounts/show/${row.id}`)
|
|
}
|
|
}
|
|
|
|
const openOwnAccount = (rowLike: any) => {
|
|
const row = rowLike?.original || rowLike
|
|
if (row?.id) {
|
|
router.push(`/standardEntity/ownaccounts/show/${row.id}`)
|
|
}
|
|
}
|
|
|
|
onMounted(setupPage)
|
|
</script>
|
|
|
|
<template>
|
|
<UDashboardNavbar title="BWA">
|
|
|
|
</UDashboardNavbar>
|
|
|
|
<UDashboardPanelContent class="min-w-0 space-y-6 overflow-x-hidden overflow-y-auto p-4 md:p-6">
|
|
<div class="flex flex-col gap-3 md:flex-row md:items-end">
|
|
<UFormField label="Jahr" class="w-full md:w-48">
|
|
<USelectMenu
|
|
v-model="selectedYear"
|
|
:items="yearItems"
|
|
value-key="value"
|
|
label-key="label"
|
|
class="w-full"
|
|
/>
|
|
</UFormField>
|
|
|
|
<UFormField label="Monat" class="w-full md:w-56">
|
|
<USelectMenu
|
|
v-model="selectedMonth"
|
|
:items="monthItems"
|
|
value-key="value"
|
|
label-key="label"
|
|
class="w-full"
|
|
/>
|
|
</UFormField>
|
|
</div>
|
|
|
|
<div class="grid min-w-0 gap-4 md:grid-cols-2 xl:grid-cols-4">
|
|
<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>
|
|
<div class="mt-2 text-sm text-gray-500 dark:text-gray-400">
|
|
{{ incomeDocumentCount }} gebuchte Ausgangsbelege
|
|
</div>
|
|
</UCard>
|
|
|
|
<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-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">Einnahmen Belege</div>
|
|
<div class="mt-2 text-2xl font-semibold">{{ incomeDocumentCount }}</div>
|
|
<div class="mt-2 text-sm text-gray-500 dark:text-gray-400">
|
|
Ausgangsbelege im Zeitraum
|
|
</div>
|
|
</UCard>
|
|
|
|
<UCard class="min-w-0">
|
|
<div class="text-sm text-gray-500 dark:text-gray-400">Ausgaben Belege</div>
|
|
<div class="mt-2 text-2xl font-semibold">{{ expenseDocumentCount }}</div>
|
|
<div class="mt-2 text-sm text-gray-500 dark:text-gray-400">
|
|
Eingangsbelege plus direkte Buchungen
|
|
</div>
|
|
</UCard>
|
|
</div>
|
|
|
|
<div class="grid min-w-0 gap-4 md:grid-cols-2">
|
|
<UCard class="min-w-0">
|
|
<div class="text-sm text-gray-500 dark:text-gray-400">Betriebsergebnis</div>
|
|
<div class="mt-2 text-2xl font-semibold" :class="operatingResult >= 0 ? 'text-primary-500' : 'text-error'">
|
|
{{ useCurrency(operatingResult) }}
|
|
</div>
|
|
<div class="mt-2 text-sm text-gray-500 dark:text-gray-400">
|
|
Einnahmen minus Ausgaben netto
|
|
</div>
|
|
</UCard>
|
|
|
|
<UCard class="min-w-0">
|
|
<div class="text-sm text-gray-500 dark:text-gray-400">USt-Saldo</div>
|
|
<div class="mt-2 text-2xl font-semibold" :class="taxSummary.balance >= 0 ? 'text-amber-600 dark:text-amber-400' : 'text-primary-500'">
|
|
{{ useCurrency(taxSummary.balance) }}
|
|
</div>
|
|
<div class="mt-2 text-sm text-gray-500 dark:text-gray-400">
|
|
USt {{ useCurrency(taxSummary.outputTax) }} | Vorsteuer {{ useCurrency(taxSummary.inputTax) }}
|
|
</div>
|
|
</UCard>
|
|
</div>
|
|
|
|
<div class="grid min-w-0 gap-4 xl:grid-cols-2">
|
|
<UCard class="min-w-0">
|
|
<template #header>
|
|
<div class="font-semibold">USt-Details</div>
|
|
</template>
|
|
|
|
<div class="space-y-3 text-sm">
|
|
<div class="flex items-center justify-between">
|
|
<span>Netto 19% Ausgangsbelege</span>
|
|
<span>{{ useCurrency(taxSummary.output.net19) }}</span>
|
|
</div>
|
|
<div class="flex items-center justify-between">
|
|
<span>USt 19%</span>
|
|
<span>{{ useCurrency(taxSummary.output.tax19) }}</span>
|
|
</div>
|
|
<div class="flex items-center justify-between">
|
|
<span>Netto 7% Ausgangsbelege</span>
|
|
<span>{{ useCurrency(taxSummary.output.net7) }}</span>
|
|
</div>
|
|
<div class="flex items-center justify-between">
|
|
<span>USt 7%</span>
|
|
<span>{{ useCurrency(taxSummary.output.tax7) }}</span>
|
|
</div>
|
|
<div class="flex items-center justify-between">
|
|
<span>Steuerfrei</span>
|
|
<span>{{ useCurrency(taxSummary.output.net0 + taxSummary.input.net0) }}</span>
|
|
</div>
|
|
</div>
|
|
</UCard>
|
|
|
|
<UCard class="min-w-0">
|
|
<template #header>
|
|
<div class="font-semibold">Vorsteuer-Details</div>
|
|
</template>
|
|
|
|
<div class="space-y-3 text-sm">
|
|
<div class="flex items-center justify-between">
|
|
<span>Netto 19% Eingangsbelege</span>
|
|
<span>{{ useCurrency(taxSummary.input.net19) }}</span>
|
|
</div>
|
|
<div class="flex items-center justify-between">
|
|
<span>Vorsteuer 19%</span>
|
|
<span>{{ useCurrency(taxSummary.input.tax19) }}</span>
|
|
</div>
|
|
<div class="flex items-center justify-between">
|
|
<span>Netto 7% Eingangsbelege</span>
|
|
<span>{{ useCurrency(taxSummary.input.net7) }}</span>
|
|
</div>
|
|
<div class="flex items-center justify-between">
|
|
<span>Vorsteuer 7%</span>
|
|
<span>{{ useCurrency(taxSummary.input.tax7) }}</span>
|
|
</div>
|
|
<div class="flex items-center justify-between">
|
|
<span>Steuerfrei</span>
|
|
<span>{{ useCurrency(taxSummary.input.net0) }}</span>
|
|
</div>
|
|
</div>
|
|
</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">
|
|
<span class="font-semibold">Buchungskonten</span>
|
|
<UBadge color="neutral" variant="soft">{{ accountRows.length }}</UBadge>
|
|
</div>
|
|
</template>
|
|
|
|
<div class="min-w-0">
|
|
<UTable
|
|
:data="accountRows"
|
|
:columns="normalizeTableColumns(accountColumns)"
|
|
:loading="loading"
|
|
:on-select="openAccount"
|
|
>
|
|
<template #empty>
|
|
<div class="flex flex-col items-center justify-center py-10 text-center">
|
|
<UIcon name="i-heroicons-circle-stack-20-solid" class="mb-2 h-10 w-10 text-gray-400" />
|
|
<p class="font-medium">Keine Buchungskonten im ausgewaehlten Zeitraum</p>
|
|
</div>
|
|
</template>
|
|
|
|
<template #label-cell="{ row }">
|
|
<div class="truncate font-medium">{{ row.original.label }}</div>
|
|
</template>
|
|
|
|
<template #bookings-cell="{ row }">
|
|
<div class="text-right">{{ row.original.bookings }}</div>
|
|
</template>
|
|
|
|
<template #net-cell="{ row }">
|
|
<div class="text-right tabular-nums">{{ useCurrency(row.original.net) }}</div>
|
|
</template>
|
|
|
|
<template #tax-cell="{ row }">
|
|
<div class="text-right tabular-nums">{{ useCurrency(row.original.tax) }}</div>
|
|
</template>
|
|
|
|
<template #gross-cell="{ row }">
|
|
<div class="text-right font-medium tabular-nums">{{ useCurrency(row.original.gross) }}</div>
|
|
</template>
|
|
</UTable>
|
|
</div>
|
|
</UCard>
|
|
|
|
<UCard class="min-w-0">
|
|
<template #header>
|
|
<div class="flex items-center justify-between gap-3">
|
|
<span class="font-semibold">Eigene Buchungskonten</span>
|
|
<UBadge color="neutral" variant="soft">{{ ownAccountRows.length }}</UBadge>
|
|
</div>
|
|
</template>
|
|
|
|
<div class="min-w-0">
|
|
<UTable
|
|
:data="ownAccountRows"
|
|
:columns="normalizeTableColumns(ownAccountColumns)"
|
|
:loading="loading"
|
|
:on-select="openOwnAccount"
|
|
>
|
|
<template #empty>
|
|
<div class="flex flex-col items-center justify-center py-10 text-center">
|
|
<UIcon name="i-heroicons-circle-stack-20-solid" class="mb-2 h-10 w-10 text-gray-400" />
|
|
<p class="font-medium">Keine eigenen Buchungen im ausgewaehlten Zeitraum</p>
|
|
</div>
|
|
</template>
|
|
|
|
<template #label-cell="{ row }">
|
|
<div class="truncate font-medium">{{ row.original.label }}</div>
|
|
</template>
|
|
|
|
<template #bookings-cell="{ row }">
|
|
<div class="text-right">{{ row.original.bookings }}</div>
|
|
</template>
|
|
|
|
<template #income-cell="{ row }">
|
|
<div class="text-right text-primary-500 tabular-nums">{{ useCurrency(row.original.income) }}</div>
|
|
</template>
|
|
|
|
<template #expenses-cell="{ row }">
|
|
<div class="text-right text-error tabular-nums">{{ useCurrency(row.original.expenses) }}</div>
|
|
</template>
|
|
|
|
<template #balance-cell="{ row }">
|
|
<div class="text-right font-medium tabular-nums" :class="row.original.balance >= 0 ? 'text-primary-500' : 'text-error'">
|
|
{{ useCurrency(row.original.balance) }}
|
|
</div>
|
|
</template>
|
|
</UTable>
|
|
</div>
|
|
</UCard>
|
|
</div>
|
|
</UDashboardPanelContent>
|
|
</template>
|