From 6301c342e4a87b22c4fde4fbda00691e4470d45c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=BCnrher?= Date: Thu, 10 Sep 2026 09:50:14 +0200 Subject: [PATCH] Automatischer Zahlungsparser --- .../Event/Views/Partials/ParticipantsList.vue | 85 +++- .../AcceptRefund/AcceptRefundCommand.php | 31 +- .../AcceptRefund/AcceptRefundRequest.php | 11 +- .../CreateRefundDocumentCommand.php | 33 +- .../ReleaseRefund/ReleaseRefundCommand.php | 32 ++ .../Controllers/RefundPageController.php | 28 +- .../ParticipantRefund/Views/RefundPage.vue | 217 ++++++++-- app/Enumerations/RefundAccountSource.php | 47 +++ .../AbstractEventPaymentModule.php | 16 + app/EventPaymentModules/CLAUDE.md | 36 +- .../DTO/GetRefundDataRequest.php | 23 ++ .../DTO/GetRefundDataResponse.php | 33 ++ .../EventPaymentModule.php | 14 + .../Modules/AccountTransferPaymentModule.php | 38 ++ .../Modules/UndefinedPaymentModule.php | 22 + .../RefundReleasedMail.php | 13 + app/Models/EventParticipant.php | 19 + app/Resources/EventParticipantResource.php | 26 ++ app/Support/Iban.php | 35 ++ ..._14_140010_add_refund_own_account_text.php | 46 +++ .../emails/events/refund_released.blade.php | 74 +++- tests/Feature/RefundCashPayerTest.php | 347 ++++++++++++++++ tests/Feature/RefundKnownAccountTest.php | 375 ++++++++++++++++++ tests/Unit/RefundDataTest.php | 174 ++++++++ 24 files changed, 1692 insertions(+), 83 deletions(-) create mode 100644 app/Enumerations/RefundAccountSource.php create mode 100644 app/EventPaymentModules/DTO/GetRefundDataRequest.php create mode 100644 app/EventPaymentModules/DTO/GetRefundDataResponse.php create mode 100644 database/migrations/2026_09_14_140010_add_refund_own_account_text.php create mode 100644 tests/Feature/RefundCashPayerTest.php create mode 100644 tests/Feature/RefundKnownAccountTest.php create mode 100644 tests/Unit/RefundDataTest.php diff --git a/app/Domains/Event/Views/Partials/ParticipantsList.vue b/app/Domains/Event/Views/Partials/ParticipantsList.vue index 72ffa32..bc85933 100644 --- a/app/Domains/Event/Views/Partials/ParticipantsList.vue +++ b/app/Domains/Event/Views/Partials/ParticipantsList.vue @@ -86,6 +86,16 @@ const retainedAmount = computed(() => { const hasRetention = computed(() => retainedAmount.value > 0); +/** + * Das Konto, das die Zahlungsart kennt -- bei der Überweisung das des Zahlungseingangs. + * + * Ist es da, wird es weder erfragt noch bearbeitet: Erstattet wird auf das Konto, von dem der Beitrag + * kam, und genau das steht hier. `null`, solange nichts bekannt ist (Barzahlung, Altbestand). + */ +const knownRefundAccount = computed( + () => showParticipant.value?.refundData?.available ? showParticipant.value.refundData : null +); + const retainedAmountReadable = computed( () => retainedAmount.value.toFixed(2).replace('.', ',') + ' Euro' ); @@ -121,7 +131,8 @@ const refundFormComplete = computed(() => { } } - if (refundForm.captureMode === 'management') { + // Beim bekannten Konto gibt es nichts einzugeben -- es steht fest. + if (refundForm.captureMode === 'management' && !knownRefundAccount.value) { return refundForm.accountOwner.trim() !== '' && refundForm.accountIban.trim() !== ''; } @@ -429,7 +440,7 @@ function validateRefund() { // 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.captureMode === 'management' && !knownRefundAccount.value) { if (!refundForm.accountOwner.trim()) { refundErrors.accountOwner = 'Bitte gib an, wem das Konto gehört.'; } @@ -456,9 +467,14 @@ 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 : '', + // Leer beim Weg über den Teili -- dann verschickt der Server nur den Link. Beim + // Sofort-Einreichen mit bekanntem Konto geht dieses mit; eingegeben wurde nichts. + accountOwner: refundForm.captureMode === 'management' + ? (knownRefundAccount.value?.accountOwner ?? refundForm.accountOwner) + : '', + accountIban: refundForm.captureMode === 'management' + ? (knownRefundAccount.value?.accountIban ?? refundForm.accountIban) + : '', // Spende: kein Konto, trotzdem sofort eingereicht. donation: refundForm.captureMode === 'donation', // Leer bei voller Erstattung -- dann gibt es nichts zu begründen. @@ -805,14 +821,36 @@ function mailToGroup(groupKey) { Liegt die Bankverbindung schon vor oder will der Teili spenden, entfällt der Umweg über ihn: die Erstattung wird sofort eingereicht. Er bekommt den Beleg trotzdem. --> + +
+ Konto aus dem Zahlungseingang + {{ knownRefundAccount.accountOwner }} + + +
+