feat: correct total tax on incoming invoices
This commit is contained in:
@@ -46,9 +46,7 @@ const currentBalance = computed(() => {
|
||||
})
|
||||
|
||||
const getIncomingInvoiceGross = (invoice) => {
|
||||
return Number((invoice.accounts || []).reduce((sum, account) => {
|
||||
return sum + Number(account.amountNet || 0) + Number(account.amountTax || 0)
|
||||
}, 0))
|
||||
return Number(useSum().getIncomingInvoiceSum(invoice))
|
||||
}
|
||||
|
||||
const getIncomingInvoiceOpenAmount = (invoice) => {
|
||||
|
||||
@@ -68,9 +68,7 @@ const buildEntries = (rows, type, labelBuilder) =>
|
||||
}))
|
||||
|
||||
const getIncomingInvoiceGross = (invoice) => {
|
||||
return Number((invoice.accounts || []).reduce((sum, account) => {
|
||||
return sum + Number(account.amountNet || 0) + Number(account.amountTax || 0)
|
||||
}, 0))
|
||||
return Number(useSum().getIncomingInvoiceSum(invoice))
|
||||
}
|
||||
|
||||
const getIncomingInvoiceOpenAmount = (invoice) => {
|
||||
|
||||
@@ -230,13 +230,7 @@ const calculateOpenSum = (statement) => {
|
||||
}
|
||||
|
||||
const getInvoiceSum = (invoice, onlyOpenSum) => {
|
||||
let sum = 0
|
||||
if (invoice.accounts) {
|
||||
invoice.accounts.forEach(account => {
|
||||
sum += (account.amountTax || 0)
|
||||
sum += (account.amountNet || 0)
|
||||
})
|
||||
}
|
||||
let sum = Number(useSum().getIncomingInvoiceSum(invoice))
|
||||
|
||||
if (onlyOpenSum) sum = sum + Number(invoice.statementallocations.reduce((n, {amount}) => n + amount, 0))
|
||||
|
||||
|
||||
@@ -130,13 +130,7 @@ const separateIBAN = (input) => {
|
||||
}
|
||||
|
||||
const getInvoiceSum = (invoice, onlyOpenSum) => {
|
||||
let sum = 0
|
||||
if (invoice.accounts) {
|
||||
invoice.accounts.forEach(account => {
|
||||
sum += (account.amountTax || 0)
|
||||
sum += (account.amountNet || 0)
|
||||
})
|
||||
}
|
||||
let sum = Number(useSum().getIncomingInvoiceSum(invoice))
|
||||
|
||||
if (onlyOpenSum) sum = sum + Number(invoice.statementallocations.reduce((n, {amount}) => n + amount, 0))
|
||||
|
||||
|
||||
@@ -103,6 +103,8 @@ watch(() => itemInfo.value.date, (value) => {
|
||||
|
||||
// --- Berechnungslogik ---
|
||||
const useNetMode = ref(false)
|
||||
const editingTotalTax = ref(false)
|
||||
const totalTaxDraft = ref(null)
|
||||
|
||||
const taxOptions = ref([
|
||||
{ label: "19% USt", percentage: 19, key: "19" },
|
||||
@@ -186,24 +188,17 @@ const totalCalculated = computed(() => {
|
||||
}
|
||||
})
|
||||
|
||||
totalGross = Number(totalNet + totalAmount19Tax + totalAmount7Tax)
|
||||
const calculatedTax = Number(totalAmount19Tax + totalAmount7Tax)
|
||||
const hasTaxOverride = itemInfo.value.taxAmountOverride !== null && itemInfo.value.taxAmountOverride !== undefined && itemInfo.value.taxAmountOverride !== ""
|
||||
const totalTax = hasTaxOverride ? Number(itemInfo.value.taxAmountOverride) : calculatedTax
|
||||
totalGross = Number(totalNet + totalTax)
|
||||
|
||||
return { totalNet, totalAmount19Tax, totalAmount7Tax, totalGross }
|
||||
return { totalNet, totalAmount19Tax, totalAmount7Tax, calculatedTax, totalTax, totalGross, hasTaxOverride }
|
||||
})
|
||||
|
||||
const hasAmount = (value) => value !== null && value !== undefined && value !== ""
|
||||
const hasValidNumber = (value) => hasAmount(value) && Number.isFinite(Number(value))
|
||||
const isDepreciationItem = (item) => isDepreciationBookingMode(item?.bookingMode)
|
||||
const getCalculatedTax = (item) => {
|
||||
const taxRate = Number(taxOptions.value.find((tax) => tax.key === item.taxType)?.percentage || 0)
|
||||
|
||||
return Number((Number(item.amountNet || 0) * (taxRate / 100)).toFixed(2))
|
||||
}
|
||||
const hasManualTaxDifference = (item) => {
|
||||
if (!hasValidNumber(item.amountTax) || !hasValidNumber(item.amountNet)) return false
|
||||
|
||||
return Math.abs(Number(item.amountTax) - getCalculatedTax(item)) >= 0.005
|
||||
}
|
||||
|
||||
const updateBookingMode = (item) => {
|
||||
ensureDepreciationDefaults(item, itemInfo.value.date)
|
||||
@@ -226,14 +221,6 @@ const recalculateItem = (item, source) => {
|
||||
calculateFromNet()
|
||||
} else if (source === 'gross') {
|
||||
calculateFromGross()
|
||||
} else if (source === 'tax') {
|
||||
if(!hasValidNumber(item.amountTax)) return
|
||||
|
||||
if((useNetMode.value || !hasAmount(item.amountGross)) && hasAmount(item.amountNet)) {
|
||||
item.amountGross = Number((Number(item.amountNet) + Number(item.amountTax)).toFixed(2))
|
||||
} else if(hasAmount(item.amountGross)) {
|
||||
item.amountNet = Number((Number(item.amountGross) - Number(item.amountTax)).toFixed(2))
|
||||
}
|
||||
} else if (source === 'taxType' || source === 'manual') {
|
||||
if(hasAmount(item.amountNet)) calculateFromNet()
|
||||
else if(hasAmount(item.amountGross)) calculateFromGross()
|
||||
@@ -246,6 +233,19 @@ const moveGrossToNet = (item) => {
|
||||
recalculateItem(item, 'net')
|
||||
}
|
||||
|
||||
const startEditingTotalTax = () => {
|
||||
totalTaxDraft.value = totalCalculated.value.totalTax.toFixed(2)
|
||||
editingTotalTax.value = true
|
||||
}
|
||||
|
||||
const applyTotalTaxOverride = () => {
|
||||
if (!hasValidNumber(totalTaxDraft.value)) return
|
||||
|
||||
const value = Number(Number(totalTaxDraft.value).toFixed(2))
|
||||
itemInfo.value.taxAmountOverride = Math.abs(value - totalCalculated.value.calculatedTax) >= 0.005 ? value : null
|
||||
editingTotalTax.value = false
|
||||
}
|
||||
|
||||
// --- Saving ---
|
||||
const updateIncomingInvoice = async (setBooked = false) => {
|
||||
if (setBooked && hasBlockingIncomingInvoiceErrors.value) {
|
||||
@@ -889,30 +889,13 @@ const hasBlockingIncomingInvoiceErrors = computed(() => blockingIncomingInvoiceE
|
||||
</div>
|
||||
|
||||
<div class="col-span-6 md:col-span-3">
|
||||
<UFormField label="Steuerbetrag" help="Kann bei Rundungsabweichungen angepasst werden">
|
||||
<UInput
|
||||
class="w-full"
|
||||
type="number"
|
||||
step="0.01"
|
||||
:model-value="item.amountTax"
|
||||
:disabled="mode === 'show'"
|
||||
@update:model-value="(val) => { item.amountTax = Number(val); recalculateItem(item, 'tax') }"
|
||||
>
|
||||
<UFormField label="Steuerbetrag" help="Automatisch berechnet">
|
||||
<UInput class="w-full" :model-value="item.amountTax" disabled color="gray">
|
||||
<template #trailing>€</template>
|
||||
</UInput>
|
||||
</UFormField>
|
||||
</div>
|
||||
|
||||
<div v-if="hasManualTaxDifference(item)" class="col-span-12">
|
||||
<UAlert
|
||||
color="warning"
|
||||
variant="soft"
|
||||
icon="i-heroicons-exclamation-triangle"
|
||||
title="Steuerbetrag manuell angepasst"
|
||||
description="FEDEO verwendet diesen Betrag für Auswertungen und Summen. Im DATEV-Export wird bei der Automatikbuchung nur der Bruttobetrag mit Steuerschlüssel übertragen; DATEV berechnet die Steuer dort erneut."
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="col-span-12 flex justify-end gap-2">
|
||||
<UButton
|
||||
size="xs"
|
||||
@@ -958,14 +941,34 @@ const hasBlockingIncomingInvoiceErrors = computed(() => blockingIncomingInvoiceE
|
||||
<span>Netto Gesamt</span>
|
||||
<span>{{ totalCalculated.totalNet.toFixed(2) }} €</span>
|
||||
</div>
|
||||
<div class="flex justify-between text-gray-500" v-if="totalCalculated.totalAmount7Tax > 0">
|
||||
<span>+ 7% USt</span>
|
||||
<span>{{ totalCalculated.totalAmount7Tax.toFixed(2) }} €</span>
|
||||
</div>
|
||||
<div class="flex justify-between text-gray-500" v-if="totalCalculated.totalAmount19Tax > 0">
|
||||
<span>+ 19% USt</span>
|
||||
<span>{{ totalCalculated.totalAmount19Tax.toFixed(2) }} €</span>
|
||||
<div class="flex items-center justify-between gap-3 text-gray-500">
|
||||
<span class="flex items-center gap-2">
|
||||
USt gesamt
|
||||
<UBadge v-if="totalCalculated.hasTaxOverride" size="xs" color="warning" variant="soft">Manuell</UBadge>
|
||||
</span>
|
||||
<div v-if="editingTotalTax" class="flex items-center gap-1">
|
||||
<UInput v-model="totalTaxDraft" type="number" step="0.01" size="xs" class="w-28">
|
||||
<template #trailing>€</template>
|
||||
</UInput>
|
||||
<UButton icon="i-heroicons-check" size="xs" variant="ghost" @click="applyTotalTaxOverride" />
|
||||
<UButton icon="i-heroicons-x-mark" size="xs" color="neutral" variant="ghost" @click="editingTotalTax = false" />
|
||||
</div>
|
||||
<div v-else class="flex items-center gap-1">
|
||||
<span>{{ totalCalculated.totalTax.toFixed(2) }} €</span>
|
||||
<UButton
|
||||
v-if="mode !== 'show'"
|
||||
icon="i-heroicons-pencil"
|
||||
size="xs"
|
||||
color="neutral"
|
||||
variant="ghost"
|
||||
aria-label="Gesamten USt-Betrag bearbeiten"
|
||||
@click="startEditingTotalTax"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<p v-if="totalCalculated.hasTaxOverride" class="text-xs text-amber-600 dark:text-amber-400">
|
||||
DATEV berechnet die USt aus dem Bruttobetrag erneut. Der Export wird mit „USt prüfen“ markiert.
|
||||
</p>
|
||||
<div class="flex justify-between font-bold text-xl text-gray-900 dark:text-white pt-2 border-t dark:border-gray-700">
|
||||
<span>Rechnungsbetrag</span>
|
||||
<span>{{ totalCalculated.totalGross.toFixed(2) }} €</span>
|
||||
|
||||
@@ -141,12 +141,7 @@ const displayCurrency = (value, currency = "€") => {
|
||||
return `${Number(value).toFixed(2).replace(".",",")} ${currency}`
|
||||
}
|
||||
const getInvoiceSum = (invoice) => {
|
||||
let sum = 0
|
||||
invoice.accounts.forEach(account => {
|
||||
sum += account.amountTax
|
||||
sum += account.amountNet
|
||||
})
|
||||
return sum.toFixed(2)
|
||||
return useSum().getIncomingInvoiceSum(invoice)
|
||||
}
|
||||
|
||||
const getPaidAmount = (item) => {
|
||||
|
||||
Reference in New Issue
Block a user