Include manual tax accounts in VAT evaluation
All checks were successful
Build and Push Docker Images / build-central-services-api (push) Successful in 35s
Build and Push Docker Images / build-central-services-admin (push) Successful in 35s
Build and Push Docker Images / build-backend (push) Successful in 57s
Build and Push Docker Images / build-frontend (push) Successful in 1m58s
Build and Push Docker Images / build-website (push) Successful in 36s
Build and Push Docker Images / build-docs (push) Successful in 34s
All checks were successful
Build and Push Docker Images / build-central-services-api (push) Successful in 35s
Build and Push Docker Images / build-central-services-admin (push) Successful in 35s
Build and Push Docker Images / build-backend (push) Successful in 57s
Build and Push Docker Images / build-frontend (push) Successful in 1m58s
Build and Push Docker Images / build-website (push) Successful in 36s
Build and Push Docker Images / build-docs (push) Successful in 34s
This commit is contained in:
20
backend/db/migrations/0063_skr03_output_tax_account.sql
Normal file
20
backend/db/migrations/0063_skr03_output_tax_account.sql
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
UPDATE "accounts"
|
||||||
|
SET "label" = 'Umsatzsteuer 19 %',
|
||||||
|
"description" = NULL
|
||||||
|
WHERE "accountChart" = 'skr03'
|
||||||
|
AND "number" = '1776';
|
||||||
|
--> statement-breakpoint
|
||||||
|
INSERT INTO "accounts" ("number", "label", "description", "accountChart")
|
||||||
|
SELECT '1776', 'Umsatzsteuer 19 %', NULL, 'skr03'
|
||||||
|
WHERE NOT EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM "accounts"
|
||||||
|
WHERE "accountChart" = 'skr03'
|
||||||
|
AND "number" = '1776'
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
SELECT setval(
|
||||||
|
pg_get_serial_sequence('accounts', 'id'),
|
||||||
|
GREATEST(COALESCE((SELECT MAX("id") FROM "accounts"), 1), 1),
|
||||||
|
true
|
||||||
|
);
|
||||||
@@ -421,6 +421,13 @@
|
|||||||
"when": 1786284000000,
|
"when": 1786284000000,
|
||||||
"tag": "0062_incoming_invoice_tax_override",
|
"tag": "0062_incoming_invoice_tax_override",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 60,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1786287600000,
|
||||||
|
"tag": "0063_skr03_output_tax_account",
|
||||||
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import {
|
|||||||
formatTaxEvaluationPeriodRange,
|
formatTaxEvaluationPeriodRange,
|
||||||
getCreatedDocumentTaxBreakdown,
|
getCreatedDocumentTaxBreakdown,
|
||||||
getIncomingInvoiceTaxBreakdown,
|
getIncomingInvoiceTaxBreakdown,
|
||||||
|
getManualBookingTaxBreakdown,
|
||||||
getTaxEvaluationPeriodBounds,
|
getTaxEvaluationPeriodBounds,
|
||||||
normalizeTaxEvaluationPeriod
|
normalizeTaxEvaluationPeriod
|
||||||
} from "~/composables/useTaxEvaluation"
|
} from "~/composables/useTaxEvaluation"
|
||||||
@@ -40,7 +41,10 @@ const loadSummary = async () => {
|
|||||||
const periodType = normalizeTaxEvaluationPeriod(auth.activeTenantData?.taxEvaluationPeriod)
|
const periodType = normalizeTaxEvaluationPeriod(auth.activeTenantData?.taxEvaluationPeriod)
|
||||||
const bounds = getTaxEvaluationPeriodBounds(dayjs(), periodType)
|
const bounds = getTaxEvaluationPeriodBounds(dayjs(), periodType)
|
||||||
|
|
||||||
const { createdDocuments: docs, incomingInvoices: incoming } = await loadCoreData()
|
const [{ createdDocuments: docs, incomingInvoices: incoming }, manualBookings] = await Promise.all([
|
||||||
|
loadCoreData(),
|
||||||
|
useNuxtApp().$api("/api/banking/manual-bookings") as Promise<any[]>
|
||||||
|
])
|
||||||
|
|
||||||
const outputDocs = (docs || []).filter((doc: any) => {
|
const outputDocs = (docs || []).filter((doc: any) => {
|
||||||
if (doc?.state !== "Gebucht") return false
|
if (doc?.state !== "Gebucht") return false
|
||||||
@@ -67,12 +71,28 @@ const loadSummary = async () => {
|
|||||||
return sum + breakdown.tax19 + breakdown.tax7
|
return sum + breakdown.tax19 + breakdown.tax7
|
||||||
}, 0)
|
}, 0)
|
||||||
|
|
||||||
|
const manualTax = (manualBookings || [])
|
||||||
|
.filter((booking: any) => {
|
||||||
|
const date = dayjs(booking.manualBookingDate)
|
||||||
|
return date.isValid() && !date.isBefore(bounds.start, "day") && !date.isAfter(bounds.end, "day")
|
||||||
|
})
|
||||||
|
.reduce((sum: { outputTax19: number; inputTax19: number }, booking: any) => {
|
||||||
|
const breakdown = getManualBookingTaxBreakdown(booking)
|
||||||
|
return {
|
||||||
|
outputTax19: sum.outputTax19 + breakdown.outputTax19,
|
||||||
|
inputTax19: sum.inputTax19 + breakdown.inputTax19,
|
||||||
|
}
|
||||||
|
}, { outputTax19: 0, inputTax19: 0 })
|
||||||
|
|
||||||
|
const totalOutputTax = outputTax + manualTax.outputTax19
|
||||||
|
const totalInputTax = inputTax + manualTax.inputTax19
|
||||||
|
|
||||||
summary.value = {
|
summary.value = {
|
||||||
label: formatTaxEvaluationPeriodLabel(bounds.start, periodType),
|
label: formatTaxEvaluationPeriodLabel(bounds.start, periodType),
|
||||||
range: formatTaxEvaluationPeriodRange(bounds.start, periodType),
|
range: formatTaxEvaluationPeriodRange(bounds.start, periodType),
|
||||||
outputTax: Number(outputTax.toFixed(2)),
|
outputTax: Number(totalOutputTax.toFixed(2)),
|
||||||
inputTax: Number(inputTax.toFixed(2)),
|
inputTax: Number(totalInputTax.toFixed(2)),
|
||||||
balance: Number((outputTax - inputTax).toFixed(2)),
|
balance: Number((totalOutputTax - totalInputTax).toFixed(2)),
|
||||||
outputCount: outputDocs.length,
|
outputCount: outputDocs.length,
|
||||||
inputCount: inputDocs.length,
|
inputCount: inputDocs.length,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -166,3 +166,33 @@ export const getIncomingInvoiceTaxBreakdown = (invoice: any) => {
|
|||||||
net0: Number(breakdown.net0.toFixed(2)),
|
net0: Number(breakdown.net0.toFixed(2)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getSkr03AccountNumber = (account: any) => {
|
||||||
|
if (!account || String(account.accountChart || "").toLowerCase() !== "skr03") return null
|
||||||
|
return String(account.number || "")
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getManualBookingTaxBreakdown = (booking: any) => {
|
||||||
|
const amount = Number(booking?.amount || 0)
|
||||||
|
const breakdown = { outputTax19: 0, inputTax19: 0 }
|
||||||
|
|
||||||
|
if (!Number.isFinite(amount) || amount === 0) return breakdown
|
||||||
|
|
||||||
|
const applySide = (account: any, side: "debit" | "credit") => {
|
||||||
|
const accountNumber = getSkr03AccountNumber(account)
|
||||||
|
|
||||||
|
if (accountNumber === "1576") {
|
||||||
|
breakdown.inputTax19 += side === "debit" ? amount : -amount
|
||||||
|
} else if (accountNumber === "1776") {
|
||||||
|
breakdown.outputTax19 += side === "credit" ? amount : -amount
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
applySide(booking.account, "debit")
|
||||||
|
applySide(booking.contraAccount, "credit")
|
||||||
|
|
||||||
|
return {
|
||||||
|
outputTax19: Number(breakdown.outputTax19.toFixed(2)),
|
||||||
|
inputTax19: Number(breakdown.inputTax19.toFixed(2)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import {
|
|||||||
formatTaxEvaluationPeriodRange,
|
formatTaxEvaluationPeriodRange,
|
||||||
getCreatedDocumentTaxBreakdown,
|
getCreatedDocumentTaxBreakdown,
|
||||||
getIncomingInvoiceTaxBreakdown,
|
getIncomingInvoiceTaxBreakdown,
|
||||||
|
getManualBookingTaxBreakdown,
|
||||||
getTaxEvaluationPeriodBounds,
|
getTaxEvaluationPeriodBounds,
|
||||||
normalizeTaxEvaluationPeriod,
|
normalizeTaxEvaluationPeriod,
|
||||||
shiftTaxEvaluationPeriodStart
|
shiftTaxEvaluationPeriodStart
|
||||||
@@ -18,6 +19,7 @@ const auth = useAuthStore()
|
|||||||
const loading = ref(true)
|
const loading = ref(true)
|
||||||
const createdDocuments = ref<any[]>([])
|
const createdDocuments = ref<any[]>([])
|
||||||
const incomingInvoices = ref<any[]>([])
|
const incomingInvoices = ref<any[]>([])
|
||||||
|
const manualBookings = ref<any[]>([])
|
||||||
|
|
||||||
const periodType = computed(() => normalizeTaxEvaluationPeriod(auth.activeTenantData?.taxEvaluationPeriod))
|
const periodType = computed(() => normalizeTaxEvaluationPeriod(auth.activeTenantData?.taxEvaluationPeriod))
|
||||||
|
|
||||||
@@ -40,13 +42,15 @@ const loadData = async () => {
|
|||||||
loading.value = true
|
loading.value = true
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const [docs, incoming] = await Promise.all([
|
const [docs, incoming, manual] = await Promise.all([
|
||||||
useEntities("createddocuments").select(),
|
useEntities("createddocuments").select(),
|
||||||
useEntities("incominginvoices").select()
|
useEntities("incominginvoices").select(),
|
||||||
|
useNuxtApp().$api("/api/banking/manual-bookings")
|
||||||
])
|
])
|
||||||
|
|
||||||
createdDocuments.value = (docs || []).filter(isRelevantOutputDocument)
|
createdDocuments.value = (docs || []).filter(isRelevantOutputDocument)
|
||||||
incomingInvoices.value = (incoming || []).filter(isRelevantInputInvoice)
|
incomingInvoices.value = (incoming || []).filter(isRelevantInputInvoice)
|
||||||
|
manualBookings.value = (manual as any[]) || []
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false
|
loading.value = false
|
||||||
}
|
}
|
||||||
@@ -69,6 +73,19 @@ const periods = computed(() => {
|
|||||||
return date.isValid() && !date.isBefore(bounds.start, "day") && !date.isAfter(bounds.end, "day")
|
return date.isValid() && !date.isBefore(bounds.start, "day") && !date.isAfter(bounds.end, "day")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const manualTax = manualBookings.value
|
||||||
|
.filter((booking) => {
|
||||||
|
const date = dayjs(booking.manualBookingDate)
|
||||||
|
return date.isValid() && !date.isBefore(bounds.start, "day") && !date.isAfter(bounds.end, "day")
|
||||||
|
})
|
||||||
|
.reduce((sum, booking) => {
|
||||||
|
const breakdown = getManualBookingTaxBreakdown(booking)
|
||||||
|
return {
|
||||||
|
outputTax19: sum.outputTax19 + breakdown.outputTax19,
|
||||||
|
inputTax19: sum.inputTax19 + breakdown.inputTax19,
|
||||||
|
}
|
||||||
|
}, { outputTax19: 0, inputTax19: 0 })
|
||||||
|
|
||||||
const output = outputDocs.reduce((sum, doc) => {
|
const output = outputDocs.reduce((sum, doc) => {
|
||||||
const breakdown = getCreatedDocumentTaxBreakdown(doc)
|
const breakdown = getCreatedDocumentTaxBreakdown(doc)
|
||||||
return {
|
return {
|
||||||
@@ -91,6 +108,9 @@ const periods = computed(() => {
|
|||||||
}
|
}
|
||||||
}, { net19: 0, tax19: 0, net7: 0, tax7: 0, net0: 0 })
|
}, { net19: 0, tax19: 0, net7: 0, tax7: 0, net0: 0 })
|
||||||
|
|
||||||
|
output.tax19 = Number((output.tax19 + manualTax.outputTax19).toFixed(2))
|
||||||
|
input.tax19 = Number((input.tax19 + manualTax.inputTax19).toFixed(2))
|
||||||
|
|
||||||
const outputTax = Number((output.tax19 + output.tax7).toFixed(2))
|
const outputTax = Number((output.tax19 + output.tax7).toFixed(2))
|
||||||
const inputTax = Number((input.tax19 + input.tax7).toFixed(2))
|
const inputTax = Number((input.tax19 + input.tax7).toFixed(2))
|
||||||
const balance = Number((outputTax - inputTax).toFixed(2))
|
const balance = Number((outputTax - inputTax).toFixed(2))
|
||||||
@@ -146,7 +166,7 @@ onMounted(loadData)
|
|||||||
</h2>
|
</h2>
|
||||||
<p class="text-sm text-gray-500 dark:text-gray-400">
|
<p class="text-sm text-gray-500 dark:text-gray-400">
|
||||||
Intervall: {{ periodType === "monthly" ? "monatlich" : periodType === "quarterly" ? "quartalsweise" : "jährlich" }}.
|
Intervall: {{ periodType === "monthly" ? "monatlich" : periodType === "quarterly" ? "quartalsweise" : "jährlich" }}.
|
||||||
Berücksichtigt werden gebuchte Ausgangsrechnungen, Abschlags- und Stornorechnungen sowie gebuchte Eingangsbelege mit Datum.
|
Berücksichtigt werden gebuchte Ausgangsrechnungen, Abschlags- und Stornorechnungen, gebuchte Eingangsbelege sowie manuelle Buchungen auf SKR03 1576 und 1776.
|
||||||
</p>
|
</p>
|
||||||
<p v-if="currentPeriod" class="text-sm text-gray-500 dark:text-gray-400">
|
<p v-if="currentPeriod" class="text-sm text-gray-500 dark:text-gray-400">
|
||||||
{{ currentPeriod.range }}
|
{{ currentPeriod.range }}
|
||||||
|
|||||||
Reference in New Issue
Block a user