diff --git a/app/Domains/Admin/Controllers/TenantPaymentMethodsGetController.php b/app/Domains/Admin/Controllers/TenantPaymentMethodsGetController.php index 824a7d4..59d1380 100644 --- a/app/Domains/Admin/Controllers/TenantPaymentMethodsGetController.php +++ b/app/Domains/Admin/Controllers/TenantPaymentMethodsGetController.php @@ -5,6 +5,7 @@ namespace App\Domains\Admin\Controllers; use App\Models\AvailablePaymentMethod; use App\Resources\AvailablePaymentMethodResource; use App\Scopes\CommonController; +use App\ValueObjects\BankStatementRuleset; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; @@ -16,6 +17,10 @@ class TenantPaymentMethodsGetController extends CommonController 'paymentMethods' => AvailablePaymentMethod::all() ->map(fn (AvailablePaymentMethod $method) => new AvailablePaymentMethodResource($method)->toArray($request)), 'saveEndpoint' => '/api/v1/admin/tenant/payment-methods', + // Der app-weite Standard für das Kontoauszug-Format. Das Formular zeigt ihn als + // Vorbelegung an, damit erkennbar ist, wovon ein Override abweicht. + 'statementRulesetDefault' => BankStatementRuleset::default()->toArray(), + 'statementRulesetCharsets' => BankStatementRuleset::CHARSETS, ]); } } diff --git a/app/Domains/Admin/Views/Partials/TenantPaymentMethods.vue b/app/Domains/Admin/Views/Partials/TenantPaymentMethods.vue index 1f60daa..a660416 100644 --- a/app/Domains/Admin/Views/Partials/TenantPaymentMethods.vue +++ b/app/Domains/Admin/Views/Partials/TenantPaymentMethods.vue @@ -1,5 +1,6 @@ + + + + diff --git a/app/Domains/Event/Views/Partials/CommonSettings.vue b/app/Domains/Event/Views/Partials/CommonSettings.vue index bed9e87..c46e2ea 100644 --- a/app/Domains/Event/Views/Partials/CommonSettings.vue +++ b/app/Domains/Event/Views/Partials/CommonSettings.vue @@ -27,6 +27,8 @@ const emit = defineEmits(['close']) contributingLocalGroups: contributingLocalGroups.value, eventName: props.event.name, eventLocation: props.event.location, + street: props.event.street ?? '', + houseNumber: props.event.houseNumber ?? '', postalCode: props.event.postalCode, email: props.event.email, earlyBirdEnd: props.event.earlyBirdEnd.internal, @@ -35,6 +37,8 @@ const emit = defineEmits(['close']) eatingHabits: eatingHabits.value, sendWeeklyReports: props.event.sendWeeklyReports, registrationAllowed: props.event.registrationAllowed, + shortRegistration: props.event.shortRegistration, + swimmingPermissionRequired: props.event.swimmingPermissionRequired, flatSupport: props.event.flatSupportEdit, supportPerson: props.event.supportPersonIndex, }) @@ -57,6 +61,8 @@ const emit = defineEmits(['close']) body: { eventName: formData.eventName, eventLocation: formData.eventLocation, + street: formData.street, + houseNumber: formData.houseNumber, postalCode: formData.postalCode, email: formData.email, earlyBirdEnd: formData.earlyBirdEnd, @@ -64,6 +70,8 @@ const emit = defineEmits(['close']) alcoholicsAge: formData.alcoholicsAge, sendWeeklyReports: formData.sendWeeklyReports, registrationAllowed: formData.registrationAllowed, + shortRegistration: formData.shortRegistration, + swimmingPermissionRequired: formData.swimmingPermissionRequired, flatSupport: formData.flatSupport, supportPerson: formData.supportPerson, contributingLocalGroups: contributingLocalGroups.value, @@ -105,6 +113,20 @@ const emit = defineEmits(['close']) + + Straße (optional) + + + + + + + Hausnummer (optional) + + + + + Postleitzahl des Veranstaltungsorts @@ -172,6 +194,27 @@ const emit = defineEmits(['close']) + + + + +
+ + Fragt nur die nötigsten Daten ab (Name, Kontakt, Allergien, Foto-Erlaubnis). + Nicht erhobene Angaben wie Anschrift und An-/Abreise werden automatisch gefüllt. + + + + + + + +
+ + Ist die Abfrage deaktiviert, wird für Minderjährige „Keine Badeerlaubnis" hinterlegt. + + + diff --git a/app/Domains/Event/Views/Partials/Overview.vue b/app/Domains/Event/Views/Partials/Overview.vue index 870365f..2630d20 100644 --- a/app/Domains/Event/Views/Partials/Overview.vue +++ b/app/Domains/Event/Views/Partials/Overview.vue @@ -6,6 +6,7 @@ import EventAddons from "./EventAddons.vue"; import ParticipationSummary from "./ParticipationSummary.vue"; import CommonSettings from "./CommonSettings.vue"; import EventManagement from "./EventManagement.vue"; +import BankStatementImport from "./BankStatementImport.vue"; import Modal from "../../../../Views/Components/Modal.vue"; import MailCompose from "./MailCompose.vue"; import FullScreenModal from "../../../../Views/Components/FullScreenModal.vue"; @@ -21,6 +22,12 @@ const props = defineProps({ const displayData = ref('main'); const showEventData = ref(false); + const showBankStatement = ref(false); + + // Nach dem Buchen stimmen die Beitragsstände der Übersicht nicht mehr -- neu laden. + async function bankStatementBooked() { + await showMain(); + } async function showMain() { @@ -117,9 +124,18 @@ async function showEventAddons() {
+ +
+ + + @@ -158,6 +174,7 @@ async function showEventAddons() {
+



diff --git a/app/Domains/Event/Views/Partials/ParticipantData.vue b/app/Domains/Event/Views/Partials/ParticipantData.vue index eb5b6b6..15ad0e3 100644 --- a/app/Domains/Event/Views/Partials/ParticipantData.vue +++ b/app/Domains/Event/Views/Partials/ParticipantData.vue @@ -233,6 +233,7 @@ function saveParticipant() { {{ props.participant.localgroup }} 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. --> + + +