149 lines
4.0 KiB
Vue
149 lines
4.0 KiB
Vue
<script setup>
|
|
const props = defineProps({
|
|
modelValue: {
|
|
type: Array,
|
|
default: () => []
|
|
},
|
|
disabled: {
|
|
type: Boolean,
|
|
default: false
|
|
}
|
|
})
|
|
|
|
const emit = defineEmits(["update:modelValue"])
|
|
const toast = useToast()
|
|
|
|
const accounts = ref([])
|
|
const ibanSearch = ref("")
|
|
const showCreate = ref(false)
|
|
|
|
const createPayload = ref({
|
|
iban: "",
|
|
bic: "",
|
|
bankName: "",
|
|
description: ""
|
|
})
|
|
|
|
const normalizeIban = (value) => String(value || "").replace(/\s+/g, "").toUpperCase()
|
|
|
|
const loadAccounts = async () => {
|
|
accounts.value = await useEntities("entitybankaccounts").select()
|
|
}
|
|
|
|
const assignedIds = computed(() => {
|
|
return Array.isArray(props.modelValue) ? props.modelValue : []
|
|
})
|
|
|
|
const assignedAccounts = computed(() => {
|
|
return accounts.value.filter((a) => assignedIds.value.includes(a.id))
|
|
})
|
|
|
|
const updateAssigned = (ids) => {
|
|
emit("update:modelValue", ids)
|
|
}
|
|
|
|
const assignByIban = async () => {
|
|
const search = normalizeIban(ibanSearch.value)
|
|
if (!search) return
|
|
|
|
const match = accounts.value.find((a) => normalizeIban(a.iban) === search)
|
|
if (!match) {
|
|
toast.add({ title: "Kein Bankkonto mit dieser IBAN gefunden.", color: "rose" })
|
|
return
|
|
}
|
|
|
|
if (assignedIds.value.includes(match.id)) {
|
|
toast.add({ title: "Dieses Bankkonto ist bereits zugewiesen.", color: "amber" })
|
|
return
|
|
}
|
|
|
|
updateAssigned([...assignedIds.value, match.id])
|
|
ibanSearch.value = ""
|
|
}
|
|
|
|
const removeAssigned = (id) => {
|
|
updateAssigned(assignedIds.value.filter((i) => i !== id))
|
|
}
|
|
|
|
const createAndAssign = async () => {
|
|
if (!createPayload.value.iban || !createPayload.value.bic || !createPayload.value.bankName) {
|
|
toast.add({ title: "IBAN, BIC und Bankinstitut sind Pflichtfelder.", color: "rose" })
|
|
return
|
|
}
|
|
|
|
const created = await useEntities("entitybankaccounts").create(createPayload.value, true)
|
|
await loadAccounts()
|
|
updateAssigned([...assignedIds.value, created.id])
|
|
createPayload.value = { iban: "", bic: "", bankName: "", description: "" }
|
|
showCreate.value = false
|
|
}
|
|
|
|
loadAccounts()
|
|
</script>
|
|
|
|
<template>
|
|
<div class="flex flex-col gap-2 w-full">
|
|
<div class="flex flex-wrap gap-2" v-if="assignedAccounts.length > 0">
|
|
<UBadge
|
|
v-for="account in assignedAccounts"
|
|
:key="account.id"
|
|
color="primary"
|
|
variant="subtle"
|
|
>
|
|
{{ account.displayLabel || account.iban }}
|
|
<UButton
|
|
v-if="!disabled"
|
|
variant="ghost"
|
|
color="gray"
|
|
size="2xs"
|
|
icon="i-heroicons-x-mark"
|
|
class="ml-1"
|
|
@click="removeAssigned(account.id)"
|
|
/>
|
|
</UBadge>
|
|
</div>
|
|
|
|
<InputGroup class="w-full">
|
|
<UInput
|
|
v-model="ibanSearch"
|
|
class="flex-auto"
|
|
placeholder="IBAN eingeben und zuweisen"
|
|
:disabled="disabled"
|
|
@keydown.enter.prevent="assignByIban"
|
|
/>
|
|
<UButton :disabled="disabled" @click="assignByIban">
|
|
Zuweisen
|
|
</UButton>
|
|
<UButton :disabled="disabled" color="gray" variant="outline" @click="showCreate = true">
|
|
Neu
|
|
</UButton>
|
|
</InputGroup>
|
|
</div>
|
|
|
|
<UModal v-model="showCreate">
|
|
<UCard>
|
|
<template #header>Neue Bankverbindung erstellen</template>
|
|
<div class="space-y-3">
|
|
<UFormGroup label="IBAN">
|
|
<UInput v-model="createPayload.iban" />
|
|
</UFormGroup>
|
|
<UFormGroup label="BIC">
|
|
<UInput v-model="createPayload.bic" />
|
|
</UFormGroup>
|
|
<UFormGroup label="Bankinstitut">
|
|
<UInput v-model="createPayload.bankName" />
|
|
</UFormGroup>
|
|
<UFormGroup label="Beschreibung (optional)">
|
|
<UInput v-model="createPayload.description" />
|
|
</UFormGroup>
|
|
</div>
|
|
<template #footer>
|
|
<div class="flex justify-end gap-2">
|
|
<UButton color="gray" variant="outline" @click="showCreate = false">Abbrechen</UButton>
|
|
<UButton @click="createAndAssign">Erstellen und zuweisen</UButton>
|
|
</div>
|
|
</template>
|
|
</UCard>
|
|
</UModal>
|
|
</template>
|