Refundings without contacting the participant
This commit is contained in:
@@ -10,6 +10,7 @@ import AmountInput from "../../../../Views/Components/AmountInput.vue";
|
||||
import FullScreenModal from "../../../../Views/Components/FullScreenModal.vue";
|
||||
import DialableTelephoneNumber from "../../../../Views/Components/DialableTelephoneNumber.vue";
|
||||
import ErrorText from "../../../../Views/Components/ErrorText.vue";
|
||||
import IbanInput from "../../../../Views/Components/IbanInput.vue";
|
||||
|
||||
const props = defineProps({
|
||||
data: {
|
||||
@@ -47,10 +48,11 @@ const openCancelDialog = ref(false);
|
||||
const openPartialPaymentDialogSwitch = ref(false);
|
||||
const openRefundDialogSwitch = ref(false);
|
||||
|
||||
// Der Erstattungsdialog. Betrag und Grund werden hier gesetzt; die Bankverbindung erfasst der Teili
|
||||
// selbst über den Link, den die Freigabe ihm schickt.
|
||||
const refundForm = reactive({amount: '', reason: '', reasonNote: ''});
|
||||
const refundErrors = reactive({amount: '', reason: '', reasonNote: ''});
|
||||
// Der Erstattungsdialog. `captureMode` steuert den Weg: 'participant' schickt dem Teili einen Link, über
|
||||
// den er seine Bankverbindung selbst einträgt; 'management' heißt, sie liegt der Aktionsleitung bereits
|
||||
// vor -- dann wird die Erstattung sofort eingereicht.
|
||||
const refundForm = reactive({amount: '', reason: '', reasonNote: '', captureMode: 'participant', accountOwner: '', accountIban: ''});
|
||||
const refundErrors = reactive({amount: '', reason: '', reasonNote: '', accountOwner: '', accountIban: ''});
|
||||
const refundReasons = ref([]);
|
||||
const refundSaving = ref(false);
|
||||
|
||||
@@ -317,9 +319,12 @@ async function openRefundDialog(participant) {
|
||||
refundForm.amount = participant.amountPaid?.short ?? '';
|
||||
refundForm.reason = '';
|
||||
refundForm.reasonNote = '';
|
||||
refundErrors.amount = '';
|
||||
refundErrors.reason = '';
|
||||
refundErrors.reasonNote = '';
|
||||
// Vorgabe ist der übliche Weg über den Teili.
|
||||
refundForm.captureMode = 'participant';
|
||||
refundForm.accountOwner = '';
|
||||
refundForm.accountIban = '';
|
||||
|
||||
Object.keys(refundErrors).forEach(key => refundErrors[key] = '');
|
||||
|
||||
if (refundReasons.value.length === 0) {
|
||||
const reasons = await request('/api/v1/core/retrieve-refund-reasons', {method: 'GET'});
|
||||
@@ -333,9 +338,7 @@ function validateRefund() {
|
||||
const amount = Number((refundForm.amount ?? '').replace(',', '.'));
|
||||
const paid = Number(showParticipant.value?.amountPaidValue ?? 0);
|
||||
|
||||
refundErrors.amount = '';
|
||||
refundErrors.reason = '';
|
||||
refundErrors.reasonNote = '';
|
||||
Object.keys(refundErrors).forEach(key => refundErrors[key] = '');
|
||||
|
||||
if (!refundForm.amount || !(amount > 0)) {
|
||||
refundErrors.amount = 'Bitte gib einen Betrag größer als 0 ein.';
|
||||
@@ -349,7 +352,19 @@ function validateRefund() {
|
||||
refundErrors.reasonNote = 'Bitte erläutere den Grund.';
|
||||
}
|
||||
|
||||
return !refundErrors.amount && !refundErrors.reason && !refundErrors.reasonNote;
|
||||
// Beim Direktweg wird sofort eingereicht -- danach gibt es keine Gelegenheit mehr zu berichtigen.
|
||||
// Ob die IBAN wirklich stimmt, prüft der Server mit Prüfziffer und länderabhängiger Länge.
|
||||
if (refundForm.captureMode === 'management') {
|
||||
if (!refundForm.accountOwner.trim()) {
|
||||
refundErrors.accountOwner = 'Bitte gib an, wem das Konto gehört.';
|
||||
}
|
||||
|
||||
if (!refundForm.accountIban.trim()) {
|
||||
refundErrors.accountIban = 'Bitte gib die IBAN des Kontos ein.';
|
||||
}
|
||||
}
|
||||
|
||||
return Object.values(refundErrors).every(message => !message);
|
||||
}
|
||||
|
||||
async function execRefund() {
|
||||
@@ -366,13 +381,22 @@ async function execRefund() {
|
||||
amount: refundForm.amount,
|
||||
reason: refundForm.reason,
|
||||
reasonNote: refundForm.reasonNote,
|
||||
// Leer beim Weg über den Teili -- dann verschickt der Server nur den Link.
|
||||
accountOwner: refundForm.captureMode === 'management' ? refundForm.accountOwner : '',
|
||||
accountIban: refundForm.captureMode === 'management' ? refundForm.accountIban : '',
|
||||
},
|
||||
});
|
||||
|
||||
if (data?.status === 'success') {
|
||||
toast.success(data.message);
|
||||
// Reaktiv statt per getElementById: die Meta-Zeile hängt am Vorgang und wechselt mit ihm.
|
||||
// Beim Direktweg steht dort sofort "Erstattet" samt Abrechnungsnummer.
|
||||
showParticipant.value.refund = data.refund;
|
||||
// Der gezahlte Beitrag wird beim Einreichen auf 0 gesetzt -- sonst zeigte die Zeile weiter
|
||||
// den alten Stand, bis jemand neu lädt.
|
||||
if (data.refund?.status === 'accepted') {
|
||||
showParticipant.value.amountPaidValue = 0;
|
||||
}
|
||||
openRefundDialogSwitch.value = false;
|
||||
} else {
|
||||
toast.error(data?.message ?? 'Die Erstattung konnte nicht freigegeben werden.');
|
||||
@@ -603,8 +627,7 @@ function mailToGroup(groupKey) {
|
||||
>
|
||||
<p class="refund-intro">
|
||||
{{ showParticipant?.fullname }} hat
|
||||
<strong>{{ showParticipant?.amountPaid?.readable }}</strong> gezahlt. Nach der Freigabe erhält
|
||||
der Teili eine E-Mail und trägt seine Bankverbindung selbst ein.
|
||||
<strong>{{ showParticipant?.amountPaid?.readable }}</strong> gezahlt.
|
||||
</p>
|
||||
|
||||
<div class="refund-field">
|
||||
@@ -632,8 +655,49 @@ function mailToGroup(groupKey) {
|
||||
<ErrorText :message="refundErrors.reasonNote" />
|
||||
</div>
|
||||
|
||||
<!--
|
||||
Liegt die Bankverbindung schon vor, entfällt der Umweg über den Teili: die Erstattung wird
|
||||
sofort eingereicht. Er bekommt den Beleg trotzdem.
|
||||
-->
|
||||
<div class="refund-field">
|
||||
<label class="refund-choice">
|
||||
<input type="radio" value="participant" v-model="refundForm.captureMode" />
|
||||
Teilnehmer*in trägt die Bankverbindung selbst ein
|
||||
</label>
|
||||
<label class="refund-choice">
|
||||
<input type="radio" value="management" v-model="refundForm.captureMode" />
|
||||
Bankverbindung liegt mir vor
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<template v-if="refundForm.captureMode === 'management'">
|
||||
<div class="refund-field">
|
||||
<label for="refund_account_owner">Kontoinhaber*in</label>
|
||||
<input
|
||||
id="refund_account_owner"
|
||||
v-model="refundForm.accountOwner"
|
||||
type="text"
|
||||
class="form-input"
|
||||
/>
|
||||
<ErrorText :message="refundErrors.accountOwner" />
|
||||
</div>
|
||||
|
||||
<div class="refund-field">
|
||||
<label for="refund_account_iban">IBAN</label>
|
||||
<IbanInput id="refund_account_iban" v-model="refundForm.accountIban" class="form-input" />
|
||||
<ErrorText :message="refundErrors.accountIban" />
|
||||
</div>
|
||||
|
||||
<p class="refund-hint">
|
||||
Die Erstattung wird sofort als Abrechnung eingereicht. Der Teili erhält den Beleg per
|
||||
E-Mail und kann die Angaben prüfen.
|
||||
</p>
|
||||
</template>
|
||||
|
||||
<button class="button" :disabled="refundSaving" @click="execRefund()">
|
||||
{{ refundSaving ? 'Wird freigegeben…' : 'Erstattung freigeben' }}
|
||||
<template v-if="refundSaving">Wird gespeichert…</template>
|
||||
<template v-else-if="refundForm.captureMode === 'management'">Erstattung einreichen</template>
|
||||
<template v-else>Erstattung freigeben</template>
|
||||
</button>
|
||||
</Modal>
|
||||
|
||||
@@ -668,10 +732,32 @@ function mailToGroup(groupKey) {
|
||||
}
|
||||
|
||||
.refund-field select,
|
||||
.refund-field textarea {
|
||||
.refund-field textarea,
|
||||
.refund-field .form-input {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.refund-choice {
|
||||
display: block;
|
||||
margin-bottom: 6px;
|
||||
font-size: 0.9rem;
|
||||
color: #1a1a1a;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.refund-choice input {
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
.refund-hint {
|
||||
margin-bottom: 14px;
|
||||
padding: 8px 10px;
|
||||
border-left: 3px solid #f5c400;
|
||||
background-color: #fffef5;
|
||||
font-size: 0.85rem;
|
||||
color: #4b5563;
|
||||
}
|
||||
|
||||
.participants-table {
|
||||
width: 95%;
|
||||
margin: 20px auto;
|
||||
|
||||
Reference in New Issue
Block a user