SEPA-Mandate in Verträge und Ausgangsrechnungen einbauen #183

This commit is contained in:
2026-05-15 18:13:29 +02:00
parent d522cbb49d
commit 9592e2b062
2 changed files with 90 additions and 37 deletions

View File

@@ -224,6 +224,33 @@ const availableSepaMandates = computed(() => {
}) })
}) })
const getSelectedSepaMandate = () => {
return availableSepaMandates.value.find((mandate) => mandate.id === itemInfo.value.outgoingsepamandate) || null
}
const mapContractPaymentType = (paymentType) => {
if (paymentType === "Einzug") return "direct-debit"
if (paymentType === "Überweisung") return "transfer"
return null
}
const applyContractPaymentData = () => {
const selectedContract = contracts.value.find((contract) => contract.id === itemInfo.value.contract)
if (!selectedContract) return
const mappedPaymentType = mapContractPaymentType(selectedContract.paymentType)
if (mappedPaymentType) {
itemInfo.value.payment_type = mappedPaymentType
}
const contractMandateId = selectedContract.outgoingsepamandate?.id || selectedContract.outgoingsepamandate
if (mappedPaymentType === "direct-debit" && contractMandateId) {
itemInfo.value.outgoingsepamandate = contractMandateId
} else if (mappedPaymentType === "transfer") {
itemInfo.value.outgoingsepamandate = null
}
}
const applyDefaultSepaMandate = () => { const applyDefaultSepaMandate = () => {
if (itemInfo.value.payment_type !== "direct-debit") { if (itemInfo.value.payment_type !== "direct-debit") {
itemInfo.value.outgoingsepamandate = null itemInfo.value.outgoingsepamandate = null
@@ -246,6 +273,11 @@ const applyDefaultSepaMandate = () => {
itemInfo.value.outgoingsepamandate = defaultMandate?.id || null itemInfo.value.outgoingsepamandate = defaultMandate?.id || null
} }
watch(
() => itemInfo.value.contract,
() => applyContractPaymentData()
)
watch( watch(
() => [itemInfo.value.customer, itemInfo.value.contract, itemInfo.value.payment_type, outgoingsepamandates.value.length], () => [itemInfo.value.customer, itemInfo.value.contract, itemInfo.value.payment_type, outgoingsepamandates.value.length],
() => applyDefaultSepaMandate() () => applyDefaultSepaMandate()
@@ -2268,6 +2300,24 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
class="w-full" class="w-full"
/> />
</UFormField> </UFormField>
<UFormField
class="min-w-0 flex-1"
label="Individueller Aufschlag:"
>
<UInput
type="number"
step="0.01"
v-model="itemInfo.customSurchargePercentage"
@change="updateCustomSurcharge"
class="w-full"
>
<template #trailing>
<span class="text-gray-500 dark:text-gray-400 text-xs">%</span>
</template>
</UInput>
</UFormField>
</InputGroup>
<InputGroup class="w-full items-start flex-wrap md:flex-nowrap">
<UFormField <UFormField
class="min-w-0 flex-1" class="min-w-0 flex-1"
label="Zahlungsart:" label="Zahlungsart:"
@@ -2289,39 +2339,38 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
class="min-w-0 flex-1" class="min-w-0 flex-1"
label="SEPA-Mandat:" label="SEPA-Mandat:"
> >
<USelectMenu <InputGroup>
v-model="itemInfo.outgoingsepamandate" <USelectMenu
value-key="id" v-model="itemInfo.outgoingsepamandate"
label-key="reference" value-key="id"
:items="availableSepaMandates" label-key="reference"
:search-input="{ placeholder: 'Suche...' }" :items="availableSepaMandates"
:filter-fields="['reference', 'status']" :search-input="{ placeholder: 'Suche...' }"
class="w-full" :filter-fields="['reference', 'status']"
:disabled="!itemInfo.customer" class="w-full"
> :disabled="!itemInfo.customer"
<template #default> >
{{ itemInfo.outgoingsepamandate ? availableSepaMandates.find(i => i.id === itemInfo.outgoingsepamandate)?.reference : "Kein Mandat ausgewählt" }} <template #default>
</template> {{ getSelectedSepaMandate()?.reference || "Kein Mandat ausgewählt" }}
<template #item="{ item: mandate }"> </template>
{{ mandate.reference }} - {{ mandate.bankaccount?.displayLabel || "Bankverbindung" }} <template #item="{ item: mandate }">
</template> {{ mandate.reference }} - {{ mandate.bankaccount?.displayLabel || "Bankverbindung" }}
</USelectMenu> </template>
</UFormField> </USelectMenu>
<UFormField <UButton
class="min-w-0 flex-1" variant="outline"
label="Individueller Aufschlag:" color="error"
> v-if="itemInfo.outgoingsepamandate"
<UInput icon="i-heroicons-x-mark"
type="number" @click="itemInfo.outgoingsepamandate = null"
step="0.01" />
v-model="itemInfo.customSurchargePercentage" <EntityModalButtons
@change="updateCustomSurcharge" type="outgoingsepamandates"
class="w-full" :id="itemInfo.outgoingsepamandate"
> :create-query="{customer: itemInfo.customer}"
<template #trailing> @return-data="(data) => itemInfo.outgoingsepamandate = data.id"
<span class="text-gray-500 dark:text-gray-400 text-xs">%</span> />
</template> </InputGroup>
</UInput>
</UFormField> </UFormField>
</InputGroup> </InputGroup>
<UFormField <UFormField
@@ -2438,7 +2487,7 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
> >
<InputGroup> <InputGroup>
<USelectMenu <USelectMenu
:items="contracts.filter(i => i.customer?.id === itemInfo.customer && (itemInfo.plant ? itemInfo.plant === i.plant : true))" :items="contracts.filter(i => (i.customer?.id || i.customer) === itemInfo.customer && (itemInfo.plant ? itemInfo.plant === i.plant : true))"
v-model="itemInfo.contract" v-model="itemInfo.contract"
value-key="id" value-key="id"
label-key="name" label-key="name"
@@ -2463,7 +2512,7 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
@click="itemInfo.contract = null" @click="itemInfo.contract = null"
/> />
<EntityModalButtons <EntityModalButtons
type="projects" type="contracts"
:id="itemInfo.contract" :id="itemInfo.contract"
:create-query="{customer: itemInfo.customer}" :create-query="{customer: itemInfo.customer}"
@return-data="(data) => itemInfo.contract = data.id" @return-data="(data) => itemInfo.contract = data.id"

View File

@@ -957,10 +957,14 @@ export const useDataStore = defineStore('data', () => {
inputType: "select", inputType: "select",
selectDataType: "outgoingsepamandates", selectDataType: "outgoingsepamandates",
selectOptionAttribute: "reference", selectOptionAttribute: "reference",
selectSearchAttributes: ["reference"], selectSearchAttributes: ["reference", "status"],
selectDataTypeFilter: function (i, item) { selectDataTypeFilter: function (i, item) {
const mandateCustomer = i.customer?.id || i.customer const mandateCustomer = i.customer?.id || i.customer
return !item.customer || mandateCustomer === item.customer return !i.archived && i.status === "Aktiv" && (!item.customer || mandateCustomer === item.customer)
},
entityModalButtonsType: "outgoingsepamandates",
entityModalCreateQueryFunction: function (item) {
return {customer: item.customer}
}, },
showFunction: function (item) { showFunction: function (item) {
return item.paymentType === "Einzug" return item.paymentType === "Einzug"