feat(accounting): Kostenstellen von Eingangsbelegen jederzeit nachträglich ändern
Eigener Endpunkt und MCP-Tool ändern ausschließlich die Positionskostenstellen, auch bei gebuchten oder einer Bankbuchung zugewiesenen Eingangsbelegen. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -200,6 +200,47 @@ const getAccountLabel = (item) => {
|
||||
return account ? `${account.number || ""} ${account.label || ""}`.trim() : "-"
|
||||
}
|
||||
const getCostCentreLabel = (item) => costcentres.value.find((costcentre) => costcentre.id === item.costCentre)?.name || "-"
|
||||
|
||||
const canEditCostCentres = computed(() => mode.value === "show" && Boolean(itemInfo.value.id) && !itemInfo.value.archived)
|
||||
const costCentresOpen = ref(false)
|
||||
const costCentresSaving = ref(false)
|
||||
const costCentreDraft = ref([])
|
||||
const costCentreOptionLabel = (id) => {
|
||||
const centre = costcentres.value.find((item) => item.id === id)
|
||||
return centre ? [centre.number, centre.name].filter(Boolean).join(" - ") : (id ? "Bisherige Kostenstelle" : "Keine Kostenstelle")
|
||||
}
|
||||
|
||||
const openCostCentres = () => {
|
||||
costCentreDraft.value = (itemInfo.value.accounts || []).map((account, index) => ({
|
||||
index,
|
||||
label: `${index + 1}. ${account.description || getAccountLabel(account)}`,
|
||||
costcentre: account.costCentre || null,
|
||||
}))
|
||||
costCentresOpen.value = true
|
||||
}
|
||||
|
||||
const saveCostCentres = async () => {
|
||||
if (costCentresSaving.value) return
|
||||
costCentresSaving.value = true
|
||||
try {
|
||||
const accountCostCentres = costCentreDraft.value
|
||||
.filter((row) => row.costcentre !== (itemInfo.value.accounts[row.index]?.costCentre || null))
|
||||
.map(({ index, costcentre }) => ({ index, costcentre }))
|
||||
if (accountCostCentres.length) {
|
||||
const { invoice } = await useNuxtApp().$api(`/api/functions/incoming-invoices/${itemInfo.value.id}/cost-centres`, {
|
||||
method: "PUT",
|
||||
body: { accountCostCentres },
|
||||
})
|
||||
itemInfo.value.accounts = normalizeIncomingInvoiceAccounts(invoice.accounts || [], invoice.date)
|
||||
toast.add({ title: "Kostenstellen gespeichert", color: "success" })
|
||||
}
|
||||
costCentresOpen.value = false
|
||||
} catch (error) {
|
||||
toast.add({ title: "Kostenstellen konnten nicht gespeichert werden", description: error?.data?.error || "Bitte versuche es erneut.", color: "error" })
|
||||
} finally {
|
||||
costCentresSaving.value = false
|
||||
}
|
||||
}
|
||||
const getBookingModeLabel = (item) => EXPENSE_BOOKING_MODE_ITEMS.find((mode) => mode.value === item.bookingMode)?.label || "-"
|
||||
const getTaxLabel = (item) => taxOptions.value.find((tax) => tax.key === item.taxType)?.label || "-"
|
||||
|
||||
@@ -362,6 +403,14 @@ const hasBlockingIncomingInvoiceErrors = computed(() => blockingIncomingInvoiceE
|
||||
>
|
||||
Bearbeiten
|
||||
</UButton>
|
||||
<UButton
|
||||
v-if="canEditCostCentres"
|
||||
icon="i-heroicons-tag"
|
||||
variant="outline"
|
||||
@click="openCostCentres"
|
||||
>
|
||||
Kostenstellen bearbeiten
|
||||
</UButton>
|
||||
<ArchiveButton
|
||||
v-if="canArchiveIncomingInvoice"
|
||||
color="error"
|
||||
@@ -1060,6 +1109,27 @@ const hasBlockingIncomingInvoiceErrors = computed(() => blockingIncomingInvoiceE
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<UModal v-model:open="costCentresOpen" title="Kostenstellen bearbeiten" :dismissible="!costCentresSaving" :close="!costCentresSaving" :ui="{ content: 'sm:max-w-2xl' }">
|
||||
<template #body>
|
||||
<p class="mb-4 text-sm text-muted">Die Kostenstellen der Positionen können jederzeit geändert werden, auch bei gebuchten oder zugewiesenen Belegen. Alle anderen Angaben bleiben unverändert.</p>
|
||||
<div class="space-y-4">
|
||||
<UFormField v-for="row in costCentreDraft" :key="row.index" :label="row.label">
|
||||
<InputGroup>
|
||||
<USelectMenu v-model="row.costcentre" :items="costcentres" value-key="id" label-key="name" :filter-fields="['name', 'number']" class="w-full" :disabled="costCentresSaving">
|
||||
<template #default>{{ costCentreOptionLabel(row.costcentre) }}</template>
|
||||
<template #item="{ item }">{{ [item.number, item.name].filter(Boolean).join(' - ') }}</template>
|
||||
</USelectMenu>
|
||||
<UButton icon="i-heroicons-x-mark" variant="outline" :aria-label="`Kostenstelle für ${row.label} entfernen`" :disabled="costCentresSaving || !row.costcentre" @click="row.costcentre = null" />
|
||||
</InputGroup>
|
||||
</UFormField>
|
||||
</div>
|
||||
</template>
|
||||
<template #footer>
|
||||
<UButton variant="outline" :disabled="costCentresSaving" @click="costCentresOpen = false">Abbrechen</UButton>
|
||||
<UButton :loading="costCentresSaving" @click="saveCostCentres">Kostenstellen speichern</UButton>
|
||||
</template>
|
||||
</UModal>
|
||||
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
Reference in New Issue
Block a user