Automatischer Zahlungsparser
This commit is contained in:
@@ -28,8 +28,35 @@ const props = defineProps({
|
||||
reasonNote: String,
|
||||
acceptedAt: String,
|
||||
donation: Boolean,
|
||||
/*
|
||||
* Das Konto aus dem Zahlungseingang, falls bekannt: {owner, ibanMasked}.
|
||||
*
|
||||
* Ist es gesetzt, wird es nicht mehr abgefragt -- es steht bereits am Vorgang und der Server
|
||||
* nimmt ohnehin nur dieses. Die IBAN kommt maskiert an: zum Wiedererkennen genug, zum
|
||||
* Mitschreiben zu wenig.
|
||||
*/
|
||||
knownAccount: {type: Object, default: null},
|
||||
/*
|
||||
* Woher das Erstattungskonto kommt -- entschieden von der Zahlungsart, nicht hier:
|
||||
* known -- liegt vor, wird nur bestätigt
|
||||
* origin -- es gab ein Ursprungskonto, wir fragen danach
|
||||
* none -- es gab nie eines (Barzahlung); dann ist die Herkunftsfrage sinnlos
|
||||
*/
|
||||
accountSource: {type: String, default: 'origin'},
|
||||
/** Name des page_texts-Eintrags mit der zweiten Erklärung -- der Server wählt ihn. */
|
||||
accountDeclarationText: {type: String, default: 'CONFIRMATION_PARTICIPANT_REFUND_ACCOUNT'},
|
||||
})
|
||||
|
||||
const hasKnownAccount = computed(() => props.accountSource === 'known')
|
||||
|
||||
/**
|
||||
* Ob nach dem Ursprungskonto gefragt wird.
|
||||
*
|
||||
* Nur wenn es eines gab: Wer bar gezahlt hat, könnte die Frage nicht sinnvoll beantworten -- und landete
|
||||
* bei „Nein" in einer Sackgasse, die ihn auffordert, das Konto zu nennen, von dem überwiesen wurde.
|
||||
*/
|
||||
const asksForOrigin = computed(() => props.accountSource === 'origin')
|
||||
|
||||
// Der Zustand wandert in ein ref, damit die Seite nach dem Absenden umschalten kann, ohne neu zu laden.
|
||||
const state = ref(props.state)
|
||||
|
||||
@@ -70,6 +97,32 @@ const accountComplete = computed(
|
||||
|
||||
const isDonation = computed(() => decision.value === 'donation')
|
||||
|
||||
/**
|
||||
* Wann die Erklärungen des Auszahlungswegs erscheinen.
|
||||
*
|
||||
* Bekanntes Konto: sofort -- es steht ja schon da. Sonst erst, wenn die Kontoangaben vollständig sind;
|
||||
* wo nach dem Ursprungskonto gefragt wird, zusätzlich erst nach einem „Ja".
|
||||
*/
|
||||
const showDeclarations = computed(() => {
|
||||
if (decision.value !== 'payout') return false
|
||||
if (hasKnownAccount.value) return true
|
||||
if (!accountComplete.value) return false
|
||||
|
||||
return asksForOrigin.value ? sameAccount.value === true : true
|
||||
})
|
||||
|
||||
/**
|
||||
* Wann nach Kontoinhaber*in und IBAN gefragt wird.
|
||||
*
|
||||
* Überall dort, wo das Konto nicht schon feststeht -- beim Ursprungskonto-Weg allerdings erst, nachdem
|
||||
* die Herkunftsfrage bejaht wurde: Sonst tippt jemand ein Konto ab, das wir anschließend ablehnen müssen.
|
||||
*/
|
||||
const showAccountFields = computed(() => {
|
||||
if (decision.value !== 'payout' || hasKnownAccount.value) return false
|
||||
|
||||
return asksForOrigin.value ? sameAccount.value === true : true
|
||||
})
|
||||
|
||||
/**
|
||||
* Wechselt den Weg und nimmt dabei jedes Kreuz zurück.
|
||||
*
|
||||
@@ -95,8 +148,13 @@ function validate() {
|
||||
errors.declaration = form.declarationAccepted ? '' : 'Bitte bestätige die Erklärung.'
|
||||
|
||||
if (!isDonation.value) {
|
||||
errors.accountOwner = form.accountOwner.trim() ? '' : 'Bitte gib an, wem das Konto gehört.'
|
||||
errors.accountIban = form.accountIban.trim() ? '' : 'Bitte gib die IBAN des Kontos ein.'
|
||||
// Beim bekannten Konto gibt es nichts einzugeben und damit auch nichts zu prüfen -- nur die
|
||||
// Bestätigung, dass es stimmt.
|
||||
if (!hasKnownAccount.value) {
|
||||
errors.accountOwner = form.accountOwner.trim() ? '' : 'Bitte gib an, wem das Konto gehört.'
|
||||
errors.accountIban = form.accountIban.trim() ? '' : 'Bitte gib die IBAN des Kontos ein.'
|
||||
}
|
||||
|
||||
errors.accountDeclaration = form.accountDeclarationAccepted
|
||||
? ''
|
||||
: 'Bitte bestätige, dass es das Konto ist, von dem der Beitrag gezahlt wurde.'
|
||||
@@ -111,15 +169,23 @@ async function submit() {
|
||||
saving.value = true
|
||||
|
||||
// Bei einer Spende geht keine Bankverbindung mit -- es gibt keine, und der Server erwartet auch keine.
|
||||
// Beim bekannten Konto gehen ebenfalls keine Kontofelder mit: Der Server nimmt ausschließlich,
|
||||
// was am Vorgang steht, alles Mitgeschickte würde er verwerfen.
|
||||
const body = isDonation.value
|
||||
? {donation: true, declarationAccepted: form.declarationAccepted}
|
||||
: {
|
||||
donation: false,
|
||||
accountOwner: form.accountOwner,
|
||||
accountIban: form.accountIban,
|
||||
declarationAccepted: form.declarationAccepted,
|
||||
accountDeclarationAccepted: form.accountDeclarationAccepted,
|
||||
}
|
||||
: hasKnownAccount.value
|
||||
? {
|
||||
donation: false,
|
||||
declarationAccepted: form.declarationAccepted,
|
||||
accountDeclarationAccepted: form.accountDeclarationAccepted,
|
||||
}
|
||||
: {
|
||||
donation: false,
|
||||
accountOwner: form.accountOwner,
|
||||
accountIban: form.accountIban,
|
||||
declarationAccepted: form.declarationAccepted,
|
||||
accountDeclarationAccepted: form.accountDeclarationAccepted,
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await request('/api/v1/participant-refund/' + props.token + '/accept', {
|
||||
@@ -262,39 +328,84 @@ async function submit() {
|
||||
sonst tippt jemand ein Konto ab, das wir anschließend ablehnen müssen.
|
||||
-->
|
||||
<template v-else-if="decision === 'payout'">
|
||||
<h3>Soll der Betrag auf das Konto erstattet werden, von dem der Beitrag
|
||||
gezahlt wurde?</h3>
|
||||
<!--
|
||||
Konto bekannt: Es steht schon am Vorgang und stammt aus dem
|
||||
Zahlungseingang. Die Frage danach erübrigt sich, eingegeben wird nichts
|
||||
mehr -- gezeigt wird es trotzdem, damit ein falsch zugeordneter
|
||||
Zahlungseingang hier auffällt und nicht erst beim Rückläufer der Bank.
|
||||
-->
|
||||
<template v-if="hasKnownAccount">
|
||||
<h3>Wir erstatten auf das Konto, von dem dein Beitrag kam</h3>
|
||||
|
||||
<div class="choices">
|
||||
<button
|
||||
type="button"
|
||||
class="choice"
|
||||
:class="{active: sameAccount === true}"
|
||||
@click="sameAccount = true"
|
||||
>Ja</button>
|
||||
<button
|
||||
type="button"
|
||||
class="choice"
|
||||
:class="{active: sameAccount === false}"
|
||||
@click="sameAccount = false"
|
||||
>Nein</button>
|
||||
</div>
|
||||
<div class="known-account">
|
||||
<span class="known-account__owner">{{ knownAccount.owner }}</span>
|
||||
<span class="known-account__iban">{{ knownAccount.ibanMasked }}</span>
|
||||
</div>
|
||||
|
||||
<template v-if="sameAccount === false">
|
||||
<p class="hint">
|
||||
So können wir den Betrag leider nicht erstatten: Zurück geht er nur auf
|
||||
das Konto, von dem der Teilnahmebeitrag gezahlt wurde. Wurde er von
|
||||
einem anderen Konto überwiesen – etwa dem eines Elternteils
|
||||
–, gib bitte dieses an. Hilft das nicht weiter, wende dich bitte
|
||||
an die Aktionsleitung: {{ props.eventEmail }}
|
||||
Aus Sicherheitsgründen zeigen wir die IBAN nur teilweise. Gehört das
|
||||
Konto nicht zu deiner Zahlung, wende dich bitte an die Aktionsleitung:
|
||||
{{ props.eventEmail }}
|
||||
</p>
|
||||
|
||||
<button type="button" class="button" @click="reset()">
|
||||
Zurück zur Auswahl
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<template v-else-if="sameAccount === true">
|
||||
<!--
|
||||
Kein Ursprungskonto (bar gezahlt): Die Herkunftsfrage entfällt. Sonst
|
||||
landete der Teili bei „Nein" in einer Sackgasse, die ihn nach dem Konto
|
||||
fragt, von dem überwiesen wurde -- es gab keines. Erstattet wird auf ein
|
||||
Konto, das ihm gehört.
|
||||
-->
|
||||
<template v-else-if="!asksForOrigin">
|
||||
<h3>Auf welches Konto sollen wir erstatten?</h3>
|
||||
|
||||
<p class="choice-hint">
|
||||
Deinen Beitrag hast du nicht überwiesen, deshalb brauchen wir eine
|
||||
Bankverbindung von dir. Bitte gib ein Konto an, das auf deinen Namen
|
||||
läuft oder über das du verfügen darfst.
|
||||
</p>
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
<h3>Soll der Betrag auf das Konto erstattet werden, von dem der Beitrag
|
||||
gezahlt wurde?</h3>
|
||||
|
||||
<div class="choices">
|
||||
<button
|
||||
type="button"
|
||||
class="choice"
|
||||
:class="{active: sameAccount === true}"
|
||||
@click="sameAccount = true"
|
||||
>Ja</button>
|
||||
<button
|
||||
type="button"
|
||||
class="choice"
|
||||
:class="{active: sameAccount === false}"
|
||||
@click="sameAccount = false"
|
||||
>Nein</button>
|
||||
</div>
|
||||
|
||||
<template v-if="sameAccount === false">
|
||||
<p class="hint">
|
||||
So können wir den Betrag leider nicht erstatten: Zurück geht er nur auf
|
||||
das Konto, von dem der Teilnahmebeitrag gezahlt wurde. Wurde er von
|
||||
einem anderen Konto überwiesen – etwa dem eines Elternteils
|
||||
–, gib bitte dieses an. Hilft das nicht weiter, wende dich bitte
|
||||
an die Aktionsleitung: {{ props.eventEmail }}
|
||||
</p>
|
||||
|
||||
<button type="button" class="button" @click="reset()">
|
||||
Zurück zur Auswahl
|
||||
</button>
|
||||
</template>
|
||||
|
||||
</template>
|
||||
|
||||
<!--
|
||||
Die Kontoangaben -- gleich in beiden Wegen, in denen sie erfragt werden:
|
||||
nach einem „Ja" auf die Herkunftsfrage und bei einer Zahlungsart ohne
|
||||
Ursprungskonto. Nur beim bereits bekannten Konto entfallen sie.
|
||||
-->
|
||||
<template v-if="showAccountFields">
|
||||
<div class="field">
|
||||
<label for="account-owner">Kontoinhaber*in</label>
|
||||
<input
|
||||
@@ -312,13 +423,17 @@ async function submit() {
|
||||
<IbanInput id="account-iban" v-model="form.accountIban" class="form-input" />
|
||||
<ErrorText :message="errors.accountIban" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!--
|
||||
Die Erklärungen, die anschließend auf dem Eigenbeleg stehen. Sie
|
||||
müssen hier gelesen und angekreuzt werden -- sonst schriebe der Beleg
|
||||
dem Teili Zusicherungen zu, die er nie abgegeben hat.
|
||||
|
||||
In beiden Wegen dieselben: Beim bekannten Konto bestätigt der Teili
|
||||
Angezeigtes statt Getipptes -- der Beleg bleibt dadurch unverändert.
|
||||
-->
|
||||
<template v-if="accountComplete">
|
||||
<template v-if="showDeclarations">
|
||||
<div class="declaration">
|
||||
<input
|
||||
id="refund-declaration"
|
||||
@@ -339,7 +454,7 @@ async function submit() {
|
||||
type="checkbox"
|
||||
/>
|
||||
<TextResource
|
||||
text-name="CONFIRMATION_PARTICIPANT_REFUND_ACCOUNT"
|
||||
:text-name="accountDeclarationText"
|
||||
belongs-to="refund-account-declaration"
|
||||
/>
|
||||
</div>
|
||||
@@ -356,7 +471,6 @@ async function submit() {
|
||||
{{ saving ? 'Wird gespeichert…' : 'Angaben absenden' }}
|
||||
</button>
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
</form>
|
||||
</template>
|
||||
@@ -429,6 +543,31 @@ h3 {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Das bekannte Konto -- Anzeige, kein Feld. Bewusst wie ein Beleg gesetzt und nicht wie ein Formular,
|
||||
damit gar nicht erst der Eindruck entsteht, hier ließe sich etwas ändern. */
|
||||
.known-account {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
padding: 12px 14px;
|
||||
border: 1px solid #d1d5db;
|
||||
border-radius: 8px;
|
||||
background-color: #f9fafb;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.known-account__owner {
|
||||
font-weight: bold;
|
||||
color: #374151;
|
||||
}
|
||||
|
||||
.known-account__iban {
|
||||
font-family: monospace;
|
||||
font-size: 1.05rem;
|
||||
letter-spacing: 0.05em;
|
||||
color: #4b5563;
|
||||
}
|
||||
|
||||
.field {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user