Files
FEDEO/frontend/pages/createDocument/show/[id].vue
florianfederspiel 94ab3350ec Belegansichten um Bankbuchungsdatum erweitern #110
Zeigt Bankbuchungsdaten in Ausgangsbelegen direkt an und ergänzt Bankdetails im Modal. Überarbeitet die Eingangsbeleg-Showansicht zu einer echten Lesedarstellung mit Bankbuchungsdaten und Positionsübersicht.
2026-05-11 18:04:05 +02:00

316 lines
10 KiB
Vue

<script setup>
import CopyCreatedDocumentModal from "~/components/copyCreatedDocumentModal.vue";
import dayjs from "dayjs";
defineShortcuts({
'backspace': () => {
router.push("/createDocument")
},
})
const modal = useModal()
const route = useRoute()
const router = useRouter()
const auth = useAuthStore()
const dataStore = useDataStore()
const toast = useToast()
const itemInfo = ref({})
const linkedDocument =ref({})
const links = ref([])
const portalReleaseLoading = ref(false)
const bankBookingModalOpen = ref(false)
const portalEligibleTypes = ["invoices", "advanceInvoices", "cancellationInvoices"]
const setupPage = async () => {
if(route.params) {
if(route.params.id) itemInfo.value = await useEntities("createddocuments").selectSingle(route.params.id,"*,files(*),linkedDocument(*), statementallocations(*, bs_id(*))")
if(itemInfo.value.type === "invoices"){
const createddocuments = await useEntities("createddocuments").select()
console.log(createddocuments)
links.value = createddocuments.filter(i => i.createddocument?.id === itemInfo.value.id)
console.log(links.value)
}
linkedDocument.value = await useFiles().selectDocument(itemInfo.value.files[0].id)
}
}
setupPage()
const getStatementLike = (allocation) => allocation?.bankstatement || (typeof allocation?.bs_id === "object" ? allocation.bs_id : null)
const getStatementId = (allocation) => allocation?.bankstatement?.id || allocation?.bs_id?.id || allocation?.bankstatement || allocation?.bs_id || null
const getBankBookingDate = (allocation) => {
const statement = getStatementLike(allocation)
return statement?.date || statement?.valueDate || allocation?.manualBookingDate || null
}
const formatDate = (value) => value ? dayjs(value).format("DD.MM.YYYY") : "-"
const formatCurrency = (value) => `${Number(value || 0).toFixed(2).replace(".", ",")} EUR`
const bankBookingDates = computed(() => [...new Set(
(itemInfo.value.statementallocations || [])
.map(getBankBookingDate)
.filter(Boolean)
)].sort())
const bankBookingDateLabel = computed(() => {
if (bankBookingDates.value.length === 0) return "Kein Bankbuchungsdatum"
if (bankBookingDates.value.length === 1) return formatDate(bankBookingDates.value[0])
return bankBookingDates.value.map(formatDate).join(", ")
})
const openEmail = () => {
if(["invoices","advanceInvoices"].includes(itemInfo.value.type)){
router.push(`/email/new?loadDocuments=["${linkedDocument.value.id}"]&bcc=${encodeURIComponent(auth.activeTenantData.standardEmailForInvoices || "")}`)
} else {
router.push(`/email/new?loadDocuments=["${linkedDocument.value.id}"]`)
}
}
const openBankstatements = () => {
const statementIds = (itemInfo.value.statementallocations || []).map(getStatementId).filter(Boolean)
if(statementIds.length === 0) return
if(statementIds.length > 1) {
navigateTo(`/banking/?filter=${JSON.stringify(statementIds)}`)
} else {
navigateTo(`/banking/statements/edit/${statementIds[0]}`)
}
}
const togglePortalRelease = async () => {
if (!itemInfo.value?.id) return
portalReleaseLoading.value = true
try {
const nextValue = !itemInfo.value.availableInPortal
await useEntities("createddocuments").update(itemInfo.value.id, {
availableInPortal: nextValue
}, true)
itemInfo.value = {
...itemInfo.value,
availableInPortal: nextValue
}
toast.add({
title: nextValue ? "Für Kundenportal freigegeben" : "Portal-Freigabe entfernt"
})
} finally {
portalReleaseLoading.value = false
}
}
</script>
<template>
<UDashboardNavbar
title="Erstelltes Dokument anzeigen"
>
</UDashboardNavbar>
<UDashboardToolbar>
<template #left>
<UButton
@click="router.push(`/createDocument/edit/${itemInfo.id}`)"
v-if="itemInfo.state === 'Entwurf'"
>
Bearbeiten
</UButton>
<!-- <UButton
:to="dataStore.documents.find(i => i.createdDocument === itemInfo.id) ? dataStore.documents.find(i => i.createdDocument === itemInfo.id).url : ''"
target="_blank"
>In neuen Tab anzeigen</UButton>-->
<UButton
icon="i-heroicons-arrow-right-end-on-rectangle"
@click="modal.open(CopyCreatedDocumentModal, {
id: itemInfo.id,
type: itemInfo.type
})"
variant="outline"
>
Kopieren
</UButton>
<UButton
@click="openEmail"
icon="i-heroicons-envelope"
>
E-Mail
</UButton>
<UButton
v-if="portalEligibleTypes.includes(itemInfo.type) && itemInfo.state !== 'Entwurf'"
:icon="itemInfo.availableInPortal ? 'i-heroicons-eye-slash' : 'i-heroicons-eye'"
variant="outline"
:loading="portalReleaseLoading"
@click="togglePortalRelease"
>
{{ itemInfo.availableInPortal ? "Portal-Freigabe entfernen" : "Für Kundenportal freigeben" }}
</UButton>
<UTooltip
v-if="itemInfo.type === 'invoices' || itemInfo.type === 'advanceInvoices'"
:text="links.find(i => i.type === 'cancellationInvoices') ? 'Bereits stoniert' : ''"
>
<UButton
@click="router.push(`/createDocument/edit/?createddocument=${itemInfo.id}&loadMode=storno`)"
variant="outline"
color="error"
:disabled="links.find(i => i.type === 'cancellationInvoices')"
>
Stornieren
</UButton>
</UTooltip>
<UButton
v-if="itemInfo.project"
@click="router.push(`/standardEntity/projects/show/${itemInfo.project?.id}`)"
icon="i-heroicons-link"
variant="outline"
>
Projekt
</UButton>
<UButton
v-if="itemInfo.customer"
@click="router.push(`/standardEntity/customers/show/${itemInfo.customer?.id}`)"
icon="i-heroicons-link"
variant="outline"
>
Kunde
</UButton>
<UButton
v-if="itemInfo.plant"
@click="router.push(`/standardEntity/plants/show/${itemInfo.plant?.id}`)"
icon="i-heroicons-link"
variant="outline"
>
Objekt
</UButton>
<UButton
v-if="itemInfo.contract"
@click="router.push(`/standardEntity/contracts/show/${itemInfo.contract?.id}`)"
icon="i-heroicons-link"
variant="outline"
>
Vertrag
</UButton>
<UButton
v-if="itemInfo.contact"
@click="router.push(`/standardEntity/contacts/show/${itemInfo.contact?.id}`)"
icon="i-heroicons-link"
variant="outline"
>
Ansprechpartner
</UButton>
<UButton
v-if="itemInfo.createddocument"
@click="router.push(`/createDocument/show/${itemInfo.createddocument.id}`)"
icon="i-heroicons-link"
variant="outline"
>
{{dataStore.documentTypesForCreation[itemInfo.createddocument.type].labelSingle}} - {{itemInfo.createddocument.documentNumber}}
</UButton>
<UButton
v-for="item in itemInfo.createddocuments"
v-if="itemInfo.createddocuments"
@click="router.push(`/createDocument/show/${item.id}`)"
icon="i-heroicons-link"
variant="outline"
>
{{dataStore.documentTypesForCreation[item.type].labelSingle}} - {{item.documentNumber}}
</UButton>
<UButton
v-if="itemInfo.statementallocations?.length > 0"
@click="openBankstatements"
icon="i-heroicons-link"
variant="outline"
>
Bankbuchungen
</UButton>
<UBadge
v-if="itemInfo.statementallocations?.length > 0"
color="primary"
variant="soft"
class="self-center"
>
Bankbuchungsdatum: {{ bankBookingDateLabel }}
</UBadge>
<UButton
v-if="itemInfo.statementallocations?.length > 0"
icon="i-heroicons-calendar-days"
variant="outline"
@click="bankBookingModalOpen = true"
>
Bankdetails
</UButton>
</template>
</UDashboardToolbar>
<UModal v-model:open="bankBookingModalOpen" :ui="{ content: 'sm:max-w-2xl' }">
<template #content>
<UCard>
<template #header>
<div class="flex items-center justify-between">
<h3 class="font-semibold">Bankbuchungen</h3>
<UButton
icon="i-heroicons-x-mark"
color="gray"
variant="ghost"
@click="bankBookingModalOpen = false"
/>
</div>
</template>
<div class="space-y-3">
<div
v-for="allocation in itemInfo.statementallocations"
:key="allocation.id"
class="grid grid-cols-1 gap-2 rounded-md border border-gray-200 p-3 text-sm dark:border-gray-800 md:grid-cols-3"
>
<div>
<p class="text-xs text-gray-500">Bankbuchungsdatum</p>
<p class="font-medium">{{ formatDate(getBankBookingDate(allocation)) }}</p>
</div>
<div>
<p class="text-xs text-gray-500">Betrag</p>
<p class="font-medium">{{ formatCurrency(allocation.amount) }}</p>
</div>
<div>
<p class="text-xs text-gray-500">Text</p>
<p class="font-medium">{{ getStatementLike(allocation)?.text || allocation.description || "-" }}</p>
</div>
</div>
</div>
</UCard>
</template>
</UModal>
<UDashboardPanelContent>
<div
v-if="portalEligibleTypes.includes(itemInfo.type) && itemInfo.state !== 'Entwurf'"
class="px-4 py-3"
>
<UBadge :color="itemInfo.availableInPortal ? 'primary' : 'neutral'" variant="soft">
{{ itemInfo.availableInPortal ? "Im Kundenportal sichtbar" : "Nicht im Kundenportal freigegeben" }}
</UBadge>
</div>
<!-- <object
:data="linkedDocument.url"
class="w-full previewDocumentMobile"
/>-->
<PDFViewer v-if="linkedDocument.id" :file-id="linkedDocument.id" location="show_create_document" />
</UDashboardPanelContent>
</template>
<style scoped>
.previewDocumentMobile {
aspect-ratio: 1 / 1.414;
}
</style>