USt-Auswertung in Liquiditätsprognose integrieren
This commit is contained in:
@@ -11,7 +11,7 @@ const loading = ref(false)
|
||||
const error = ref("")
|
||||
const cacheLoaded = ref(false)
|
||||
|
||||
const CACHE_KEY = "fedeo:liquidityForecast:v1"
|
||||
const CACHE_KEY = "fedeo:liquidityForecast:v2"
|
||||
|
||||
const dismissedRecurringKeys = computed(() => {
|
||||
return tempStore.settings?.liquidityForecast?.dismissedRecurringKeys || []
|
||||
@@ -28,7 +28,8 @@ const sourceLabels = {
|
||||
open_createddocument: "Offene Ausgangsrechnung",
|
||||
open_incominginvoice: "Offener Eingangsbeleg",
|
||||
recurring_bankstatement: "Regelmäßige Bankbewegung",
|
||||
draft_createddocument: "Rechnungsentwurf"
|
||||
draft_createddocument: "Rechnungsentwurf",
|
||||
tax_settlement: "USt-Zahlung"
|
||||
}
|
||||
|
||||
const intervalLabels = {
|
||||
@@ -156,6 +157,7 @@ const formatDate = (value) => dayjs(value).format("DD.MM.YYYY")
|
||||
const getEventRoute = (event) => {
|
||||
if (event.source === "open_createddocument" && event.sourceId) return `/createDocument/show/${event.sourceId}`
|
||||
if (event.source === "open_incominginvoice" && event.sourceId) return `/incomingInvoices/show/${event.sourceId}`
|
||||
if (event.source === "tax_settlement") return "/accounting/tax"
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -245,7 +247,8 @@ const groupedEventSummary = computed(() => {
|
||||
const summary = {
|
||||
open_createddocument: { label: sourceLabels.open_createddocument, amount: 0, count: 0 },
|
||||
open_incominginvoice: { label: sourceLabels.open_incominginvoice, amount: 0, count: 0 },
|
||||
recurring_bankstatement: { label: sourceLabels.recurring_bankstatement, amount: 0, count: 0 }
|
||||
recurring_bankstatement: { label: sourceLabels.recurring_bankstatement, amount: 0, count: 0 },
|
||||
tax_settlement: { label: sourceLabels.tax_settlement, amount: 0, count: 0 }
|
||||
}
|
||||
|
||||
;(forecast.value?.events || []).forEach((event) => {
|
||||
@@ -277,6 +280,24 @@ const draftIncomeDrivers = computed(() => {
|
||||
.slice(0, 12)
|
||||
})
|
||||
|
||||
const taxPeriodTypeLabel = computed(() => {
|
||||
if (forecast.value?.tax?.periodType === "quarterly") return "quartalsweise"
|
||||
if (forecast.value?.tax?.periodType === "yearly") return "jährlich"
|
||||
return "monatlich"
|
||||
})
|
||||
|
||||
const taxForecastPeriods = computed(() => {
|
||||
return [...(forecast.value?.tax?.periods || [])]
|
||||
.filter((period) => Math.abs(Number(period.balance || 0)) > 0.01)
|
||||
.slice(0, 6)
|
||||
})
|
||||
|
||||
const taxEventDrivers = computed(() => {
|
||||
return [...(forecast.value?.events || [])]
|
||||
.filter((event) => event.source === "tax_settlement")
|
||||
.sort((a, b) => a.date.localeCompare(b.date))
|
||||
})
|
||||
|
||||
const detailedDays = computed(() => {
|
||||
let previousBalance = Number(forecast.value?.startingBalance || 0)
|
||||
|
||||
@@ -478,6 +499,79 @@ onMounted(() => {
|
||||
</UCard>
|
||||
</div>
|
||||
|
||||
<UCard v-if="taxForecastPeriods.length">
|
||||
<template #header>
|
||||
<div class="flex flex-wrap items-center justify-between gap-3">
|
||||
<div>
|
||||
<h2 class="font-semibold">USt in der Prognose</h2>
|
||||
<p class="text-sm text-gray-500">Aus der USt-Auswertung mit {{ taxPeriodTypeLabel }} Fälligkeit abgeleitet</p>
|
||||
</div>
|
||||
<UButton
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
icon="i-heroicons-arrow-top-right-on-square"
|
||||
@click="navigateTo('/accounting/tax')"
|
||||
>
|
||||
USt-Auswertung öffnen
|
||||
</UButton>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="mb-4 rounded-lg border border-dashed border-gray-300 p-4 dark:border-gray-700">
|
||||
<div class="flex flex-wrap items-center justify-between gap-3">
|
||||
<div>
|
||||
<p class="text-sm text-gray-500">Im Prognosezeitraum berücksichtigte USt-Salden</p>
|
||||
<p class="text-xs text-gray-500">Positive Salden werden als Auszahlung an das Finanzamt eingeplant, negative als Erstattung.</p>
|
||||
</div>
|
||||
<span
|
||||
class="text-lg font-semibold"
|
||||
:class="Number(forecast.tax?.totalBalance || 0) > 0 ? 'text-rose-600' : 'text-primary-600'"
|
||||
>
|
||||
{{ useCurrency(Number(forecast.tax?.totalBalance || 0) * -1) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="space-y-3">
|
||||
<div
|
||||
v-for="period in taxForecastPeriods"
|
||||
:key="period.key"
|
||||
class="grid gap-3 rounded-lg border border-gray-200 p-4 lg:grid-cols-[minmax(0,1.1fr)_minmax(0,1fr)_auto] dark:border-gray-800"
|
||||
>
|
||||
<div>
|
||||
<p class="font-medium">{{ period.label }}</p>
|
||||
<p class="text-xs text-gray-500">{{ period.range }} · Fällig am {{ formatDate(period.dueDate) }}</p>
|
||||
</div>
|
||||
<div class="grid gap-1 text-sm text-gray-500">
|
||||
<div class="flex items-center justify-between gap-3">
|
||||
<span>USt Rechnungen</span>
|
||||
<span>{{ useCurrency(period.outputTax) }}</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between gap-3">
|
||||
<span>Vorsteuer</span>
|
||||
<span>{{ useCurrency(period.inputTax) }}</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between gap-3 font-medium">
|
||||
<span>Saldo</span>
|
||||
<span :class="period.balance > 0 ? 'text-rose-600' : 'text-primary-600'">
|
||||
{{ useCurrency(period.balance) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<p class="text-xs text-gray-500">{{ period.outputCount }} Ausgangsbelege · {{ period.inputCount }} Eingangsbelege</p>
|
||||
<p
|
||||
class="mt-2 text-lg font-semibold"
|
||||
:class="period.balance > 0 ? 'text-rose-600' : 'text-primary-600'"
|
||||
>
|
||||
{{ useCurrency(period.balance * -1) }}
|
||||
</p>
|
||||
<p class="text-xs text-gray-500">Liquiditätseffekt</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</UCard>
|
||||
|
||||
<UCard v-if="draftIncomeDrivers.length">
|
||||
<template #header>
|
||||
<div>
|
||||
@@ -634,6 +728,43 @@ onMounted(() => {
|
||||
</UCard>
|
||||
</div>
|
||||
|
||||
<UCard v-if="taxEventDrivers.length">
|
||||
<template #header>
|
||||
<div>
|
||||
<h2 class="font-semibold">Geplante USt-Zahlungen und Erstattungen</h2>
|
||||
<p class="text-sm text-gray-500">Direkt aus den berücksichtigten USt-Zeiträumen abgeleitet</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="space-y-2">
|
||||
<div
|
||||
v-for="event in taxEventDrivers"
|
||||
:key="`tax-${event.date}-${event.sourceId}`"
|
||||
class="grid gap-3 rounded-lg border border-gray-200 p-3 sm:grid-cols-[110px_minmax(0,1fr)_auto_auto] dark:border-gray-800"
|
||||
>
|
||||
<span class="text-sm text-gray-500">{{ formatDate(event.date) }}</span>
|
||||
<div class="min-w-0">
|
||||
<p class="truncate font-medium">{{ event.label }}</p>
|
||||
<p class="text-xs text-gray-500">{{ sourceLabels[event.source] }}</p>
|
||||
</div>
|
||||
<span
|
||||
class="text-right font-semibold"
|
||||
:class="event.amount < 0 ? 'text-rose-600' : 'text-primary-600'"
|
||||
>
|
||||
{{ useCurrency(event.amount) }}
|
||||
</span>
|
||||
<UButton
|
||||
size="xs"
|
||||
variant="ghost"
|
||||
icon="i-heroicons-arrow-top-right-on-square"
|
||||
@click="openEvent(event)"
|
||||
>
|
||||
Öffnen
|
||||
</UButton>
|
||||
</div>
|
||||
</div>
|
||||
</UCard>
|
||||
|
||||
<div class="grid gap-4 xl:grid-cols-[minmax(0,1.2fr)_minmax(320px,0.8fr)]">
|
||||
<UCard>
|
||||
<template #header>
|
||||
|
||||
Reference in New Issue
Block a user