feat(accounting): edit cost centres from finalized outgoing documents
This commit is contained in:
@@ -22,6 +22,69 @@ const linkedDocument =ref({})
|
|||||||
const links = ref([])
|
const links = ref([])
|
||||||
const portalReleaseLoading = ref(false)
|
const portalReleaseLoading = ref(false)
|
||||||
const bankBookingModalOpen = ref(false)
|
const bankBookingModalOpen = ref(false)
|
||||||
|
const costCentresOpen = ref(false)
|
||||||
|
const costCentresLoading = ref(false)
|
||||||
|
const costCentresSaving = ref(false)
|
||||||
|
const costCentres = ref([])
|
||||||
|
const costCentreDraft = ref({ costcentre: null, rows: [] })
|
||||||
|
const costCentreId = (value) => value?.id || value || null
|
||||||
|
const costCentreLabel = (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 = async () => {
|
||||||
|
costCentresLoading.value = true
|
||||||
|
try {
|
||||||
|
costCentres.value = await useEntities("costcentres").select("*")
|
||||||
|
costCentreDraft.value = {
|
||||||
|
costcentre: costCentreId(itemInfo.value.costcentre),
|
||||||
|
rows: (itemInfo.value.rows || [])
|
||||||
|
.filter(row => row?.id != null && row.id !== "" && !["title", "subtitle", "text", "pagebreak"].includes(row.mode))
|
||||||
|
.map((row, index) => ({
|
||||||
|
rowId: String(row.id),
|
||||||
|
label: `${row.pos || index + 1}. ${row.text || row.name || row.descriptionText || "Position"}`,
|
||||||
|
costcentre: costCentreId(row.costCentre ?? row.costcentre),
|
||||||
|
})),
|
||||||
|
}
|
||||||
|
costCentresOpen.value = true
|
||||||
|
} catch (error) {
|
||||||
|
toast.add({ title: "Kostenstellen konnten nicht geladen werden", color: "error" })
|
||||||
|
} finally {
|
||||||
|
costCentresLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const saveCostCentres = async () => {
|
||||||
|
if (costCentresSaving.value) return
|
||||||
|
costCentresSaving.value = true
|
||||||
|
try {
|
||||||
|
const originalRows = new Map((itemInfo.value.rows || []).map(row => [String(row.id), row]))
|
||||||
|
const body = {
|
||||||
|
rowCostCentres: costCentreDraft.value.rows
|
||||||
|
.filter(row => row.costcentre !== costCentreId(originalRows.get(row.rowId)?.costCentre ?? originalRows.get(row.rowId)?.costcentre))
|
||||||
|
.map(({ rowId, costcentre }) => ({ rowId, costcentre })),
|
||||||
|
}
|
||||||
|
if (costCentreDraft.value.costcentre !== costCentreId(itemInfo.value.costcentre)) {
|
||||||
|
body.costcentre = costCentreDraft.value.costcentre
|
||||||
|
}
|
||||||
|
if (body.rowCostCentres.length || Object.hasOwn(body, "costcentre")) {
|
||||||
|
const { document } = await useNuxtApp().$api(`/api/functions/outgoing-documents/${itemInfo.value.id}/cost-centres`, {
|
||||||
|
method: "PUT",
|
||||||
|
body,
|
||||||
|
})
|
||||||
|
itemInfo.value.costcentre = document.costcentre
|
||||||
|
itemInfo.value.rows = document.rows
|
||||||
|
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 portalEligibleTypes = ["invoices", "advanceInvoices", "cancellationInvoices"]
|
const portalEligibleTypes = ["invoices", "advanceInvoices", "cancellationInvoices"]
|
||||||
|
|
||||||
const loadStatementAllocations = async () => {
|
const loadStatementAllocations = async () => {
|
||||||
@@ -212,6 +275,13 @@ const togglePortalRelease = async () => {
|
|||||||
>
|
>
|
||||||
Bearbeiten
|
Bearbeiten
|
||||||
</UButton>
|
</UButton>
|
||||||
|
<UButton
|
||||||
|
v-if="itemInfo.state === 'Gebucht' && itemInfo.type !== 'serialInvoices'"
|
||||||
|
icon="i-heroicons-tag"
|
||||||
|
variant="outline"
|
||||||
|
:loading="costCentresLoading"
|
||||||
|
@click="openCostCentres"
|
||||||
|
>Kostenstellen bearbeiten</UButton>
|
||||||
<!-- <UButton
|
<!-- <UButton
|
||||||
:to="dataStore.documents.find(i => i.createdDocument === itemInfo.id) ? dataStore.documents.find(i => i.createdDocument === itemInfo.id).url : ''"
|
:to="dataStore.documents.find(i => i.createdDocument === itemInfo.id) ? dataStore.documents.find(i => i.createdDocument === itemInfo.id).url : ''"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
@@ -286,6 +356,35 @@ const togglePortalRelease = async () => {
|
|||||||
|
|
||||||
</template>
|
</template>
|
||||||
</UDashboardToolbar>
|
</UDashboardToolbar>
|
||||||
|
<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 Belegkostenstelle und abweichende Positionskostenstellen können nachträglich geändert oder entfernt werden.</p>
|
||||||
|
<div class="space-y-4">
|
||||||
|
<UFormField label="Belegkostenstelle">
|
||||||
|
<InputGroup>
|
||||||
|
<USelectMenu v-model="costCentreDraft.costcentre" :items="costCentres" value-key="id" label-key="name" :filter-fields="['name', 'number']" class="w-full" :disabled="costCentresSaving">
|
||||||
|
<template #default>{{ costCentreLabel(costCentreDraft.costcentre) }}</template>
|
||||||
|
<template #item="{ item }">{{ [item.number, item.name].filter(Boolean).join(' - ') }}</template>
|
||||||
|
</USelectMenu>
|
||||||
|
<UButton icon="i-heroicons-x-mark" variant="outline" aria-label="Belegkostenstelle entfernen" :disabled="costCentresSaving || !costCentreDraft.costcentre" @click="costCentreDraft.costcentre = null" />
|
||||||
|
</InputGroup>
|
||||||
|
</UFormField>
|
||||||
|
<UFormField v-for="row in costCentreDraft.rows" :key="row.rowId" :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>{{ costCentreLabel(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>
|
||||||
<UModal v-model:open="bankBookingModalOpen" :ui="{ content: 'sm:max-w-2xl' }">
|
<UModal v-model:open="bankBookingModalOpen" :ui="{ content: 'sm:max-w-2xl' }">
|
||||||
<template #content>
|
<template #content>
|
||||||
<UCard>
|
<UCard>
|
||||||
|
|||||||
Reference in New Issue
Block a user