2. Zwischenstand
All checks were successful
Build and Push Docker Images / build-backend (push) Successful in 15s
Build and Push Docker Images / build-frontend (push) Successful in 2m43s

This commit is contained in:
2026-03-21 22:56:56 +01:00
parent 68b2cbb0ee
commit 03bcc1a939
56 changed files with 1289 additions and 1302 deletions

View File

@@ -1283,7 +1283,9 @@ const generateDocument = async () => {
}
const onChangeTab = (index) => {
if (index === 1) {
selectedTab.value = String(index)
if (String(index) === "1") {
generateDocument()
}
}
@@ -1441,13 +1443,13 @@ const saveDocument = async (state, resetup = false) => {
if (resetup) await setupPage()
}
const selectedTab = ref(0)
const selectedTab = ref("0")
const closeDocument = async () => {
if(selectedTab.value === 0) {
if(selectedTab.value === "0") {
await generateDocument()
selectedTab.value = 1
selectedTab.value = "1"
} else {
loaded.value = false
@@ -1628,7 +1630,7 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
@click="closeDocument"
v-if="itemInfo.id && itemInfo.type !== 'serialInvoices'"
>
{{selectedTab === 0 ? "Vorschau zeigen" : "Fertigstellen"}}
{{selectedTab === '0' ? "Vorschau zeigen" : "Fertigstellen"}}
</UButton>
<UButton
icon="i-mdi-content-save"
@@ -1640,8 +1642,8 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
</template>
</UDashboardNavbar>
<UDashboardPanelContent>
<UTabs class="p-5" :items="tabItems" @change="onChangeTab" v-if="loaded" v-model="selectedTab">
<template #item="{item}">
<UTabs class="p-5" :items="tabItems" @update:model-value="onChangeTab" v-if="loaded" v-model="selectedTab">
<template #content="{item}">
<div v-if="item.label === 'Editor'">
<UAlert
class="my-5"
@@ -1664,7 +1666,7 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
<InputGroup>
<div class="w-1/3 mr-5">
<UFormGroup
<UFormField
label="Dokumenttyp:"
>
<InputGroup>
@@ -1689,14 +1691,15 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
</InputGroup>
<USlideover
v-model="showAdvanceInvoiceCalcModal"
v-model:open="showAdvanceInvoiceCalcModal"
>
<UCard class="h-full">
<template #header>
<UButton @click="importPositions">Übernehmen</UButton>
</template>
<template #body>
<UCard class="h-full">
<template #header>
<UButton @click="importPositions">Übernehmen</UButton>
</template>
<UFormGroup
<UFormField
label="Gesamtsumme:"
>
<UInput
@@ -1705,8 +1708,8 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
v-model="advanceInvoiceData.totalSumNet"
@focusout="advanceInvoiceData.part = advanceInvoiceData.totalSumNet / 100 * advanceInvoiceData.partPerPecentage"
/>
</UFormGroup>
<UFormGroup
</UFormField>
<UFormField
label="Prozent:"
>
<UInput
@@ -1715,27 +1718,26 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
v-model="advanceInvoiceData.partPerPecentage"
@focusout="advanceInvoiceData.part = advanceInvoiceData.totalSumNet / 100 * advanceInvoiceData.partPerPecentage"
/>
</UFormGroup>
</UFormField>
<UFormGroup
label="Abzurechnender Anteil:"
>
<UInput
type="number"
:step="0.01"
v-model="advanceInvoiceData.part"
@focusout="advanceInvoiceData.partPerPecentage = Number((advanceInvoiceData.part / advanceInvoiceData.totalSumNet * 100).toFixed(2))"
/>
</UFormGroup>
</UCard>
<UFormField
label="Abzurechnender Anteil:"
>
<UInput
type="number"
:step="0.01"
v-model="advanceInvoiceData.part"
@focusout="advanceInvoiceData.partPerPecentage = Number((advanceInvoiceData.part / advanceInvoiceData.totalSumNet * 100).toFixed(2))"
/>
</UFormField>
</UCard>
</template>
</USlideover>
</UFormGroup>
</UFormField>
<UFormGroup
<UFormField
label="Steuertyp:"
v-if="['invoices','advanceInvoices','quotes','confirmationOrders','serialInvoices'].includes(itemInfo.type)"
>
@@ -1747,9 +1749,9 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
@change="setTaxType"
class="w-full"
></USelectMenu>
</UFormGroup>
</UFormField>
<UFormGroup
<UFormField
label="Briefpapier:"
>
<USelectMenu
@@ -1767,9 +1769,9 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
{{ itemInfo.letterhead ? letterheads.find(i => i.id === itemInfo.letterhead).name : "Kein Briefpapier gewählt" }}
</template>
</USelectMenu>
</UFormGroup>
</UFormField>
<UFormGroup
<UFormField
label="Kunde:"
>
<div class="flex flex-row">
@@ -1860,8 +1862,8 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
</UAlert>
</UFormGroup>
<UFormGroup
</UFormField>
<UFormField
label="Ansprechpartner:"
v-if="itemInfo.customer ? customers.find(i => i.id === itemInfo.customer).isCompany : false "
>
@@ -1915,9 +1917,9 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
/>
</InputGroup>
</UFormGroup>
</UFormField>
<UFormGroup
<UFormField
label="Adresse:"
>
<UInput
@@ -1949,10 +1951,10 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
:color="itemInfo.address.city ? 'primary' : 'error'"
/>
</InputGroup>
</UFormGroup>
</UFormField>
</div>
<div class="w-2/3">
<UFormGroup
<UFormField
:label="itemInfo.documentNumberTitle + ':'"
v-if="itemInfo.type !== 'serialInvoices'"
>
@@ -1961,10 +1963,10 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
placeholder="XXXX"
disabled
/>
</UFormGroup>
</UFormField>
<InputGroup class="w-full">
<UFormGroup
<UFormField
class="w-80 mr-1"
label="Lieferdatumsart:"
v-if="itemInfo.type !== 'serialInvoices'"
@@ -1975,8 +1977,8 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
/>
</UFormGroup>
<UFormGroup
</UFormField>
<UFormField
:label="`${itemInfo.deliveryDateType}${['Lieferzeitraum', 'Leistungszeitraum'].includes(itemInfo.deliveryDateType) ? ' Start' : ''}:`"
v-if="itemInfo.type !== 'serialInvoices' && itemInfo.deliveryDateType !== 'Kein Lieferdatum anzeigen'"
class="mr-1"
@@ -1994,8 +1996,8 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
</template>
</UPopover>
</UFormGroup>
<UFormGroup
</UFormField>
<UFormField
:label="itemInfo.deliveryDateType + ' Ende:'"
v-if="itemInfo.type !== 'serialInvoices' && ['Lieferzeitraum','Leistungszeitraum'].includes(itemInfo.deliveryDateType)"
>
@@ -2012,11 +2014,11 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
<LazyDatePicker v-model="itemInfo.deliveryDateEnd" @close="close"/>
</template>
</UPopover>
</UFormGroup>
</UFormField>
</InputGroup>
<InputGroup class="w-full">
<UFormGroup
<UFormField
label="Belegdatum:"
class="mr-1"
v-if="itemInfo.type !== 'serialInvoices'"
@@ -2032,10 +2034,10 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
<LazyDatePicker v-model="itemInfo.documentDate" @close="close"/>
</template>
</UPopover>
</UFormGroup>
</UFormField>
<UFormGroup
<UFormField
class="w-full"
label="Zahlungsziel in Tagen:"
>
@@ -2043,8 +2045,8 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
type="number"
v-model="itemInfo.paymentDays"
/>
</UFormGroup>
<UFormGroup
</UFormField>
<UFormField
class="w-full"
label="Zahlungsart:"
>
@@ -2066,8 +2068,8 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
{{itemInfo.payment_type === 'transfer' ? "Überweisung" : "SEPA-Lastschrift"}}
</template>
</USelectMenu>
</UFormGroup>
<UFormGroup
</UFormField>
<UFormField
class="w-full"
label="Individueller Aufschlag:"
>
@@ -2081,9 +2083,9 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
<span class="text-gray-500 dark:text-gray-400 text-xs">%</span>
</template>
</UInput>
</UFormGroup>
</UFormField>
</InputGroup>
<UFormGroup
<UFormField
label="Mitarbeiter:"
>
<USelectMenu
@@ -2093,22 +2095,22 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
value-attribute="id"
@change="setContactPersonData"
/>
</UFormGroup>
<UFormGroup
</UFormField>
<UFormField
label="Kontakt Telefon:"
>
<UInput
v-model="itemInfo.contactTel"
/>
</UFormGroup>
<UFormGroup
</UFormField>
<UFormField
label="Kontakt E-Mail:"
>
<UInput
v-model="itemInfo.contactEMail"
/>
</UFormGroup>
<UFormGroup
</UFormField>
<UFormField
label="Objekt:"
>
<InputGroup>
@@ -2145,8 +2147,8 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
/>
</InputGroup>
</UFormGroup>
<UFormGroup
</UFormField>
<UFormField
label="Projekt:"
>
<InputGroup>
@@ -2184,8 +2186,8 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
/>
</InputGroup>
</UFormGroup>
<UFormGroup
</UFormField>
<UFormField
label="Vertrag:"
>
<InputGroup>
@@ -2223,7 +2225,7 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
/>
</InputGroup>
</UFormGroup>
</UFormField>
</div>
</InputGroup>
@@ -2235,7 +2237,7 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
<div class="flex flex-row">
<div class="w-1/3">
<UFormGroup
<UFormField
label="Datum erste Ausführung:"
>
<UPopover :popper="{ placement: 'bottom-start' }">
@@ -2249,8 +2251,8 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
<LazyDatePicker v-model="itemInfo.serialConfig.firstExecution" @close="close"/>
</template>
</UPopover>
</UFormGroup>
<UFormGroup
</UFormField>
<UFormField
label="Datum letzte Ausführung:"
>
<UPopover :popper="{ placement: 'bottom-start' }">
@@ -2264,7 +2266,7 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
<LazyDatePicker v-model="itemInfo.serialConfig.executionUntil" @close="close"/>
</template>
</UPopover>
</UFormGroup>
</UFormField>
<UCheckbox
v-model="itemInfo.serialConfig.active"
label="Aktiv"
@@ -2273,22 +2275,22 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
</div>
<div class="w-2/3">
<UFormGroup
<UFormField
label="Intervall:"
>
<USelectMenu
v-model="itemInfo.serialConfig.intervall"
:options="['wöchentlich','2 - wöchentlich', 'monatlich', 'vierteljährlich','halbjährlich', 'jährlich']"
/>
</UFormGroup>
<UFormGroup
</UFormField>
<UFormField
label="Richtung:"
>
<USelectMenu
v-model="itemInfo.serialConfig.dateDirection"
:options="['Rückwirkend','Im Voraus']"
/>
</UFormGroup>
</UFormField>
<UAlert
title="Anfangs- und Enddatum"
description="Für das Anfangs- und Enddatum werden jeweils der ersten und letzte Tag des ausgewählten Intervalls und der Richtung automatisch ausgewählt"
@@ -2305,23 +2307,23 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
class="my-3"
/>
<UFormGroup
<UFormField
label="Titel:"
>
<UInput v-model="itemInfo.title" disabled/>
</UFormGroup>
<UFormGroup
</UFormField>
<UFormField
label="Beschreibung:"
class="mt-3"
>
<UInput v-model="itemInfo.description"/>
</UFormGroup>
</UFormField>
<USeparator
class="my-3"
/>
<UFormGroup
<UFormField
label="Vorlage auswählen"
>
<USelectMenu
@@ -2337,17 +2339,17 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
{{ texttemplates.find(i => i.text === itemInfo.startText && (itemInfo.type === "serialInvoices" ? i.documentType === "invoices" : i.documentType === itemInfo.type)) ? texttemplates.find(i => i.text === itemInfo.startText && (itemInfo.type === "serialInvoices" ? i.documentType === "invoices" : i.documentType === itemInfo.type)).name : "Keine Vorlage ausgewählt oder Vorlage verändert" }}
</template>
</USelectMenu>
</UFormGroup>
</UFormField>
<UFormGroup
<UFormField
label="Einleitung:"
>
<UTextarea
v-model="itemInfo.startText"
:rows="6"
/>
</UFormGroup>
</UFormField>
<USeparator
@@ -2460,7 +2462,7 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
</template>
<InputGroup class="w-full">
<UFormGroup label="Artikelkategorie:">
<UFormField label="Artikelkategorie:">
<USelectMenu
v-if="productcategories.length > 0"
:options="[{name: 'Nicht zugeordnet',id:'not set'},...productcategories]"
@@ -2468,7 +2470,7 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
option-attribute="name"
v-model="selectedProductcategorie"
/>
</UFormGroup>
</UFormField>
</InputGroup>
<UTable
:rows="selectedProductcategorie !== 'not set' ? products.filter(i => i.productcategories.includes(selectedProductcategorie)) : products.filter(i => i.productcategories.length === 0)"
@@ -2532,7 +2534,7 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
</template>
<InputGroup class="w-full">
<UFormGroup label="Leistungskategorie:">
<UFormField label="Leistungskategorie:">
<USelectMenu
v-if="servicecategories.length > 0"
:options="[{name: 'Nicht zugeordnet',id:'not set'},...servicecategories]"
@@ -2540,7 +2542,7 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
option-attribute="name"
v-model="selectedServicecategorie"
/>
</UFormGroup>
</UFormField>
</InputGroup>
<UTable
:rows="selectedServicecategorie !== 'not set' ? services.filter(i => i.servicecategories.includes(selectedServicecategorie)) : services.filter(i => i.servicecategories.length === 0)"
@@ -2671,7 +2673,8 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
@click="row.showEditDiesel = true"
/>
<UModal v-model:open="row.showEdit">
<UCard>
<template #content>
<UCard>
<!-- <template #header>
Zeile bearbeiten
</template>-->
@@ -2685,7 +2688,7 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
</div>
</template>
<InputGroup>
<UFormGroup
<UFormField
label="Anzahl:"
class="flex-auto"
>
@@ -2695,8 +2698,8 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
:step="units.find(i => i.id === row.unit) ? units.find(i => i.id === row.unit).step : '1' "
/>
</UFormGroup>
<UFormGroup
</UFormField>
<UFormField
label="Einheit:"
class="flex-auto"
>
@@ -2711,10 +2714,10 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
{{ units.find(i => i.id === row.unit) ? units.find(i => i.id === row.unit).name : "Keine Einheit gewählt" }}
</template>
</USelectMenu>
</UFormGroup>
</UFormField>
</InputGroup>
<UFormGroup
<UFormField
label="Einzelpreis:"
v-if="itemInfo.type !== 'deliveryNotes'"
>
@@ -2743,8 +2746,8 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
class="text-gray-500 dark:text-gray-400 text-xs"> </span>
</template>
</UInput>
</UFormGroup>
<UFormGroup
</UFormField>
<UFormField
label="Umsatzsteuer:"
class="mt-3"
v-if="itemInfo.type !== 'deliveryNotes'"
@@ -2761,9 +2764,9 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
{{ row.taxPercent }} %
</template>
</USelectMenu>
</UFormGroup>
</UFormField>
<UFormGroup
<UFormField
label="Rabatt:"
class="mt-3"
v-if="itemInfo.type !== 'deliveryNotes'"
@@ -2778,25 +2781,25 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
<span class="text-gray-500 dark:text-gray-400 text-xs">%</span>
</template>
</UInput>
</UFormGroup>
</UFormField>
<InputGroup class="w-full mt-3">
<UFormGroup
<UFormField
label="Optional:"
>
<UToggle
<USwitch
:disabled="row.alternative"
v-model="row.optional"
/>
</UFormGroup>
<UFormGroup
</UFormField>
<UFormField
class="ml-3"
label="Alternativ:"
>
<UToggle
<USwitch
:disabled="row.optional"
v-model="row.alternative"
/>
</UFormGroup>
</UFormField>
</InputGroup>
<UAlert
@@ -2819,7 +2822,7 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
</li>
</ul>
<UFormGroup
<UFormField
label="Beschreibung:"
class="mt-3"
>
@@ -2829,7 +2832,7 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
>
</UTextarea>
</UFormGroup>
</UFormField>
<!-- <template #footer>
<UButton
@@ -2838,16 +2841,16 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
Speichern
</UButton>
</template>-->
</UCard>
</UCard>
</template>
</UModal>
<UModal v-model:open="row.showEditDiesel">
<UCard>
<template #header>
Dieselverbrauch bearbeiten
</template>
<UFormGroup
<template #content>
<UCard>
<template #header>
Dieselverbrauch bearbeiten
</template>
<UFormField
label="Menge Diesel:"
>
<UInput
@@ -2861,8 +2864,8 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
L
</template>
</UInput>
</UFormGroup>
<UFormGroup
</UFormField>
<UFormField
label="Preis Diesel:"
>
<UInput
@@ -2875,8 +2878,8 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
€/L
</template>
</UInput>
</UFormGroup>
<UFormGroup
</UFormField>
<UFormField
label="Menge AdBlue:"
>
<UInput
@@ -2888,8 +2891,8 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
L
</template>
</UInput>
</UFormGroup>
<UFormGroup
</UFormField>
<UFormField
label="Preis AdBlue:"
>
<UInput
@@ -2901,18 +2904,17 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
€/L
</template>
</UInput>
</UFormGroup>
<template #footer>
<UButton
@click="row.showEditDiesel = false,
processDieselPosition()"
>
Speichern
</UButton>
</template>
</UCard>
</UFormField>
<template #footer>
<UButton
@click="row.showEditDiesel = false,
processDieselPosition()"
>
Speichern
</UButton>
</template>
</UCard>
</template>
</UModal>
</td>
<td
@@ -3155,7 +3157,7 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
class="my-3"
/>
<UFormGroup
<UFormField
label="Vorlage auswählen"
>
<USelectMenu
@@ -3171,16 +3173,16 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
{{texttemplates.find(i => i.text === itemInfo.endText && (itemInfo.type === "serialInvoices" ? i.documentType === "invoices" : i.documentType === itemInfo.type)) ? texttemplates.find(i => i.text === itemInfo.endText && (itemInfo.type === "serialInvoices" ? i.documentType === "invoices" : i.documentType === itemInfo.type)).name : "Keine Vorlage ausgewählt oder Vorlage verändert"}}
</template>
</USelectMenu>
</UFormGroup>
</UFormField>
<UFormGroup
<UFormField
label="Nachbemerkung:"
>
<UTextarea
v-model="itemInfo.endText"
:rows="6"
/>
</UFormGroup>
</UFormField>
</div>
<div v-else-if="item.label === 'Vorschau'">
<PDFViewer

View File

@@ -55,82 +55,82 @@
{{ getRowsForTab(item.key).length }}
</UBadge>
</template>
<template #item="{item}">
<template #content="{item}">
<div style="height: 80vh; overflow-y: scroll">
<UTable
:columns="normalizeTableColumns(getColumnsForTab(item.key))"
:empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Keine Belege anzuzeigen' }"
:empty="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Keine Belege anzuzeigen' }"
:data="getRowsForTab(item.key)"
:ui="{ divide: 'divide-gray-200 dark:divide-gray-800' }"
class="w-full"
@select="selectItem"
:on-select="selectItem"
>
<template #type-data="{row}">
<span v-if="row.type === 'cancellationInvoices'" class="text-cyan-500">{{
dataStore.documentTypesForCreation[row.type].labelSingle
}} für {{ filteredRows.find(i => row.createddocument?.id === i.id)?.documentNumber }}</span>
<span v-else>{{ dataStore.documentTypesForCreation[row.type].labelSingle }}</span>
<template #type-cell="{row}">
<span v-if="row.original.type === 'cancellationInvoices'" class="text-cyan-500">{{
dataStore.documentTypesForCreation[row.original.type].labelSingle
}} für {{ filteredRows.find(i => row.original.createddocument?.id === i.id)?.documentNumber }}</span>
<span v-else>{{ dataStore.documentTypesForCreation[row.original.type].labelSingle }}</span>
</template>
<template #state-data="{row}">
<span v-if="row.state === 'Entwurf'" class="text-rose-500">{{ row.state }}</span>
<template #state-cell="{row}">
<span v-if="row.original.state === 'Entwurf'" class="text-rose-500">{{ row.original.state }}</span>
<span
v-if="row.state === 'Gebucht' && !hasCancellationInvoice(row)"
v-if="row.original.state === 'Gebucht' && !hasCancellationInvoice(row.original)"
class="text-primary-500"
>
{{ row.state }}
{{ row.original.state }}
</span>
<span
v-else-if="row.state === 'Gebucht' && hasCancellationInvoice(row) && ['invoices','advanceInvoices'].includes(row.type)"
v-else-if="row.original.state === 'Gebucht' && hasCancellationInvoice(row.original) && ['invoices','advanceInvoices'].includes(row.original.type)"
class="text-cyan-500"
>
Storniert mit {{ getCancellationInvoice(row)?.documentNumber }}
Storniert mit {{ getCancellationInvoice(row.original)?.documentNumber }}
</span>
<span v-else-if="row.state === 'Gebucht'" class="text-primary-500">{{ row.state }}</span>
<span v-else-if="row.original.state === 'Gebucht'" class="text-primary-500">{{ row.original.state }}</span>
</template>
<template #partner-data="{row}">
<span v-if="row.customer && row.customer.name.length < 21">{{ row.customer ? row.customer.name : "" }}</span>
<UTooltip v-else-if="row.customer && row.customer.name.length > 20" :text="row.customer.name">
{{ row.customer.name.substring(0, 20) }}...
<template #partner-cell="{row}">
<span v-if="row.original.customer && row.original.customer.name.length < 21">{{ row.original.customer ? row.original.customer.name : "" }}</span>
<UTooltip v-else-if="row.original.customer && row.original.customer.name.length > 20" :text="row.original.customer.name">
{{ row.original.customer.name.substring(0, 20) }}...
</UTooltip>
</template>
<template #reference-data="{row}">
<span v-if="row === filteredRows[selectedItem]" class="text-primary-500 font-bold">{{ row.documentNumber }}</span>
<span v-else>{{ row.documentNumber }}</span>
<template #reference-cell="{row}">
<span v-if="row.original === filteredRows[selectedItem]" class="text-primary-500 font-bold">{{ row.original.documentNumber }}</span>
<span v-else>{{ row.original.documentNumber }}</span>
</template>
<template #date-data="{row}">
<span v-if="row.date">{{ row.date ? dayjs(row.date).format("DD.MM.YY") : '' }}</span>
<span v-if="row.documentDate">{{ row.documentDate ? dayjs(row.documentDate).format("DD.MM.YY") : '' }}</span>
<template #date-cell="{row}">
<span v-if="row.original.date">{{ row.original.date ? dayjs(row.original.date).format("DD.MM.YY") : '' }}</span>
<span v-if="row.original.documentDate">{{ row.original.documentDate ? dayjs(row.original.documentDate).format("DD.MM.YY") : '' }}</span>
</template>
<template #dueDate-data="{row}">
<template #dueDate-cell="{row}">
<span
v-if="row.state === 'Gebucht' && row.paymentDays && ['invoices','advanceInvoices'].includes(row.type) && !hasCancellationInvoice(row)"
:class="dayjs(row.documentDate).add(row.paymentDays,'day').diff(dayjs()) <= 0 && !isPaid(row) ? ['text-rose-500'] : '' "
v-if="row.original.state === 'Gebucht' && row.original.paymentDays && ['invoices','advanceInvoices'].includes(row.original.type) && !hasCancellationInvoice(row.original)"
:class="dayjs(row.original.documentDate).add(row.original.paymentDays,'day').diff(dayjs()) <= 0 && !isPaid(row.original) ? ['text-rose-500'] : '' "
>
{{ row.documentDate ? dayjs(row.documentDate).add(row.paymentDays, 'day').format("DD.MM.YY") : '' }}
{{ row.original.documentDate ? dayjs(row.original.documentDate).add(row.original.paymentDays, 'day').format("DD.MM.YY") : '' }}
</span>
</template>
<template #paid-data="{row}">
<template #paid-cell="{row}">
<div
v-if="(row.type === 'invoices' ||row.type === 'advanceInvoices') && row.state === 'Gebucht' && !hasCancellationInvoice(row)">
<span v-if="useSum().getIsPaid(row,items)" class="text-primary-500">Bezahlt</span>
v-if="(row.original.type === 'invoices' ||row.original.type === 'advanceInvoices') && row.original.state === 'Gebucht' && !hasCancellationInvoice(row.original)">
<span v-if="useSum().getIsPaid(row.original,items)" class="text-primary-500">Bezahlt</span>
<span v-else class="text-rose-600">Offen</span>
</div>
</template>
<template #amount-data="{row}">
<span v-if="row.type !== 'deliveryNotes'">{{ displayCurrency(useSum().getCreatedDocumentSum(row, items)) }}</span>
<template #amount-cell="{row}">
<span v-if="row.original.type !== 'deliveryNotes'">{{ displayCurrency(useSum().getCreatedDocumentSum(row.original, items)) }}</span>
</template>
<template #amountOpen-data="{row}">
<template #amountOpen-cell="{row}">
<span
v-if="!['deliveryNotes','cancellationInvoices','quotes','confirmationOrders'].includes(row.type) && row.state !== 'Entwurf' && !hasCancellationInvoice(row) && !useSum().getIsPaid(row,items) ">
{{ displayCurrency(useSum().getCreatedDocumentOpenAmount(row, items)) }}
v-if="!['deliveryNotes','cancellationInvoices','quotes','confirmationOrders'].includes(row.original.type) && row.original.state !== 'Entwurf' && !hasCancellationInvoice(row.original) && !useSum().getIsPaid(row.original,items) ">
{{ displayCurrency(useSum().getCreatedDocumentOpenAmount(row.original, items)) }}
</span>
</template>
</UTable>

View File

@@ -44,15 +44,15 @@
<USelectMenu
v-model="selectedFilters"
icon="i-heroicons-adjustments-horizontal-solid"
:options="filterOptions"
option-attribute="name"
value-attribute="name"
:items="filterOptions"
label-key="name"
value-key="name"
multiple
class="hidden lg:block"
:color="selectedFilters.length > 0 ? 'primary' : 'white'"
:ui-menu="{ width: 'min-w-max' }"
:content="{ width: 'min-w-max' }"
>
<template #label>
<template #default>
Filter
</template>
</USelectMenu>
@@ -97,12 +97,12 @@
:columns="normalizeTableColumns(columns)"
class="w-full"
:ui="{ divide: 'divide-gray-200 dark:divide-gray-800' }"
@select="(row) => router.push(`/createDocument/edit/${row.id}`)"
:empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Keine Belege anzuzeigen' }"
:on-select="(row) => router.push(`/createDocument/edit/${row.id}`)"
:empty="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Keine Belege anzuzeigen' }"
>
<template #actions-data="{ row }">
<template #actions-cell="{ row }">
<div @click.stop>
<UDropdown :items="getActionItems(row)" :popper="{ placement: 'bottom-end' }">
<UDropdown :items="getActionItems(row.original)" :popper="{ placement: 'bottom-end' }">
<UButton
color="gray"
variant="ghost"
@@ -112,51 +112,52 @@
</div>
</template>
<template #type-data="{row}">
{{dataStore.documentTypesForCreation[row.type].labelSingle}}
<template #type-cell="{row}">
{{dataStore.documentTypesForCreation[row.original.type].labelSingle}}
</template>
<template #partner-data="{row}">
<span v-if="row.customer">{{row.customer ? row.customer.name : ""}}</span>
<template #partner-cell="{row}">
<span v-if="row.original.customer">{{row.original.customer ? row.original.customer.name : ""}}</span>
</template>
<template #amount-data="{row}">
{{displayCurrency(calculateDocSum(row))}}
<template #amount-cell="{row}">
{{displayCurrency(calculateDocSum(row.original))}}
</template>
<template #serialConfig.active-data="{row}">
<span v-if="row.serialConfig.active" class="text-primary">Ja</span>
<template #serialConfig.active-cell="{row}">
<span v-if="row.original.serialConfig.active" class="text-primary">Ja</span>
<span v-else class="text-rose-600">Nein</span>
</template>
<template #contract-data="{row}">
<span v-if="row.contract">{{row.contract.contractNumber}} - {{row.contract.name}}</span>
<template #contract-cell="{row}">
<span v-if="row.original.contract">{{row.original.contract.contractNumber}} - {{row.original.contract.name}}</span>
</template>
<template #serialConfig.intervall-data="{row}">
<span v-if="row.serialConfig?.intervall === 'monatlich'">Monatlich</span>
<span v-if="row.serialConfig?.intervall === 'vierteljährlich'">Quartalsweise</span>
<template #serialConfig.intervall-cell="{row}">
<span v-if="row.original.serialConfig?.intervall === 'monatlich'">Monatlich</span>
<span v-if="row.original.serialConfig?.intervall === 'vierteljährlich'">Quartalsweise</span>
</template>
<template #payment_type-data="{row}">
<span v-if="row.payment_type === 'transfer'">Überweisung</span>
<span v-else-if="row.payment_type === 'direct-debit'">SEPA - Einzug</span>
<template #payment_type-cell="{row}">
<span v-if="row.original.payment_type === 'transfer'">Überweisung</span>
<span v-else-if="row.original.payment_type === 'direct-debit'">SEPA - Einzug</span>
</template>
</UTable>
<UModal v-model:open="showExecutionModal" :ui="{ width: 'sm:max-w-4xl' }">
<UCard>
<template #header>
<div class="flex items-center justify-between">
<h3 class="text-base font-semibold leading-6 text-gray-900 dark:text-white">
Serienrechnungen manuell ausführen
</h3>
<UButton color="gray" variant="ghost" icon="i-heroicons-x-mark-20-solid" class="-my-1" @click="showExecutionModal = false" />
</div>
</template>
<template #content>
<UCard>
<template #header>
<div class="flex items-center justify-between">
<h3 class="text-base font-semibold leading-6 text-gray-900 dark:text-white">
Serienrechnungen manuell ausführen
</h3>
<UButton color="gray" variant="ghost" icon="i-heroicons-x-mark-20-solid" class="-my-1" @click="showExecutionModal = false" />
</div>
</template>
<div class="space-y-4">
<UFormGroup label="Ausführungsdatum (Belegdatum)" help="Dieses Datum steuert auch den Leistungszeitraum (z.B. Vormonat bei 'Rückwirkend').">
<UFormField label="Ausführungsdatum (Belegdatum)" help="Dieses Datum steuert auch den Leistungszeitraum (z.B. Vormonat bei 'Rückwirkend').">
<div class="flex items-center gap-2">
<UInput type="date" v-model="executionDate" class="flex-1" />
<UButton color="gray" variant="soft" label="Heute" @click="setExecutionDateToToday" />
</div>
</UFormGroup>
</UFormField>
<USeparator label="Vorlagen auswählen" />
@@ -172,9 +173,9 @@
<USelectMenu
v-model="selectedExecutionIntervall"
:options="executionIntervallOptions"
option-attribute="label"
value-attribute="value"
:items="executionIntervallOptions"
label-key="label"
value-key="value"
size="sm"
class="w-full sm:w-52"
/>
@@ -208,20 +209,20 @@
:columns="normalizeTableColumns(executionColumns)"
:ui="{ th: { base: 'whitespace-nowrap' } }"
>
<template #partner-data="{row}">
{{row.customer ? row.customer.name : "-"}}
<template #partner-cell="{row}">
{{row.original.customer ? row.original.customer.name : "-"}}
</template>
<template #amount-data="{row}">
{{displayCurrency(calculateDocSum(row))}}
<template #amount-cell="{row}">
{{displayCurrency(calculateDocSum(row.original))}}
</template>
<template #serialConfig.intervall-data="{row}">
{{ getIntervallLabel(row.serialConfig?.intervall) }}
<template #serialConfig.intervall-cell="{row}">
{{ getIntervallLabel(row.original.serialConfig?.intervall) }}
</template>
<template #contract-data="{row}">
{{row.contract?.contractNumber}} - {{row.contract?.name}}
<template #contract-cell="{row}">
{{row.original.contract?.contractNumber}} - {{row.original.contract?.name}}
</template>
<template #plant-data="{row}">
{{ row.plant?.name || "-" }}
<template #plant-cell="{row}">
{{ row.original.plant?.name || "-" }}
</template>
</UTable>
</div>
@@ -231,58 +232,61 @@
</div>
</div>
<template #footer>
<div class="flex justify-end gap-2">
<UButton color="white" @click="showExecutionModal = false">Abbrechen</UButton>
<UButton
color="primary"
:loading="isExecuting"
:disabled="selectedExecutionRows.length === 0"
@click="executeSerialInvoices"
>
Jetzt ausführen
</UButton>
</div>
</template>
</UCard>
<template #footer>
<div class="flex justify-end gap-2">
<UButton color="white" @click="showExecutionModal = false">Abbrechen</UButton>
<UButton
color="primary"
:loading="isExecuting"
:disabled="selectedExecutionRows.length === 0"
@click="executeSerialInvoices"
>
Jetzt ausführen
</UButton>
</div>
</template>
</UCard>
</template>
</UModal>
<USlideover v-model:open="showExecutionsSlideover" :ui="{ width: 'w-screen max-w-md' }">
<UCard class="flex flex-col flex-1" :ui="{ body: { base: 'flex-1' }, ring: '', divide: 'divide-y divide-gray-100 dark:divide-gray-800' }">
<template #header>
<div class="flex items-center justify-between">
<h3 class="text-base font-semibold leading-6 text-gray-900 dark:text-white">
Alle Ausführungen
</h3>
<UButton color="gray" variant="ghost" icon="i-heroicons-x-mark-20-solid" class="-my-1" @click="showExecutionsSlideover = false" />
</div>
</template>
<div class="space-y-4 overflow-y-auto h-full p-1">
<div v-if="executionsLoading" class="flex justify-center py-4">
<UIcon name="i-heroicons-arrow-path" class="animate-spin text-gray-400 w-6 h-6" />
</div>
<div v-else-if="completedExecutions.length === 0" class="text-center text-gray-500 py-8">
Keine abgeschlossenen Ausführungen gefunden.
</div>
<div v-for="exec in completedExecutions" :key="exec.id" class="border border-gray-200 dark:border-gray-700 rounded-lg p-3">
<div class="flex justify-between items-start mb-2">
<span class="text-sm font-semibold">{{ dayjs(exec.createdAt).format('DD.MM.YYYY HH:mm') }}</span>
<UBadge :color="getStatusColor(exec.status)" variant="subtle" size="xs">
{{ getStatusLabel(exec.status) }}
</UBadge>
<template #body>
<UCard class="flex flex-col flex-1" :ui="{ body: { base: 'flex-1' }, ring: '', divide: 'divide-y divide-gray-100 dark:divide-gray-800' }">
<template #header>
<div class="flex items-center justify-between">
<h3 class="text-base font-semibold leading-6 text-gray-900 dark:text-white">
Alle Ausführungen
</h3>
<UButton color="gray" variant="ghost" icon="i-heroicons-x-mark-20-solid" class="-my-1" @click="showExecutionsSlideover = false" />
</div>
<div class="text-xs text-gray-500 grid grid-cols-2 gap-2 mt-2">
<div>
<UIcon name="i-heroicons-check-circle" class="text-green-500 w-3 h-3 align-text-bottom" />
{{exec.summary}}
</template>
<div class="space-y-4 overflow-y-auto h-full p-1">
<div v-if="executionsLoading" class="flex justify-center py-4">
<UIcon name="i-heroicons-arrow-path" class="animate-spin text-gray-400 w-6 h-6" />
</div>
<div v-else-if="completedExecutions.length === 0" class="text-center text-gray-500 py-8">
Keine abgeschlossenen Ausführungen gefunden.
</div>
<div v-for="exec in completedExecutions" :key="exec.id" class="border border-gray-200 dark:border-gray-700 rounded-lg p-3">
<div class="flex justify-between items-start mb-2">
<span class="text-sm font-semibold">{{ dayjs(exec.createdAt).format('DD.MM.YYYY HH:mm') }}</span>
<UBadge :color="getStatusColor(exec.status)" variant="subtle" size="xs">
{{ getStatusLabel(exec.status) }}
</UBadge>
</div>
<div class="text-xs text-gray-500 grid grid-cols-2 gap-2 mt-2">
<div>
<UIcon name="i-heroicons-check-circle" class="text-green-500 w-3 h-3 align-text-bottom" />
{{exec.summary}}
</div>
</div>
</div>
</div>
</div>
</UCard>
</UCard>
</template>
</USlideover>
</template>