From 8d6a4041c1faccab13d7cc872773460aaad873f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=BCnther?= Date: Wed, 29 Jul 2026 13:10:35 +0200 Subject: [PATCH] Configurations for payment modules --- .../PaymentMethodConfigurationTest.php | 181 ++++++++++++++++++ tests/Unit/PaymentMethodOptionsTest.php | 59 ++++++ 2 files changed, 240 insertions(+) create mode 100644 tests/Feature/PaymentMethodConfigurationTest.php create mode 100644 tests/Unit/PaymentMethodOptionsTest.php diff --git a/tests/Feature/PaymentMethodConfigurationTest.php b/tests/Feature/PaymentMethodConfigurationTest.php new file mode 100644 index 0000000..c7127a4 --- /dev/null +++ b/tests/Feature/PaymentMethodConfigurationTest.php @@ -0,0 +1,181 @@ +tenant = Tenant::create([ + 'slug' => 'tv', + 'name' => 'Test', + 'email' => 't@example.com', + 'email_finance' => 'finance@example.com', + 'url' => 'test.local', + 'account_name' => 'Test e.V.', + 'account_iban' => 'DE00', + 'account_bic' => 'XY', + 'city' => 'Stadt', + 'postcode' => '00000', + 'is_active_local_group' => true, + 'has_active_instance' => true, + ]); + + app()->instance('tenant', $this->tenant); + + PaymentMethod::create(['slug' => PaymentMethod::PAYMENT_ACCOUNT_TRANSACTION]); + PaymentMethod::create(['slug' => PaymentMethod::PAYMENT_NOT_DEFINED]); + + DB::table('participation_fee_types')->insert([ + 'slug' => 'FIXED', + 'name' => 'Fixed', + 'created_at' => now(), + 'updated_at' => now(), + ]); + } + + private function availableMethod(string $slug, bool $active = false, array $config = []): AvailablePaymentMethod + { + return AvailablePaymentMethod::create([ + 'tenant' => $this->tenant->slug, + 'slug' => $slug, + 'name' => 'Konto', + 'description' => null, + 'active' => $active, + 'configuration' => $config, + ]); + } + + public function test_activation_is_blocked_when_required_options_missing(): void + { + $method = $this->availableMethod(PaymentMethod::PAYMENT_ACCOUNT_TRANSACTION); + + $response = new UpdateAvailablePaymentMethodAction(new UpdateAvailablePaymentMethodRequest( + availablePaymentMethod: $method, + name: 'Konto', + description: null, + active: true, + configuration: ['iban' => 'DE123'], // account_owner fehlt + ))->execute(); + + $this->assertFalse($response->success); + $this->assertFalse($method->fresh()->active); + } + + public function test_activation_succeeds_when_configuration_complete(): void + { + $method = $this->availableMethod(PaymentMethod::PAYMENT_ACCOUNT_TRANSACTION); + + $response = new UpdateAvailablePaymentMethodAction(new UpdateAvailablePaymentMethodRequest( + availablePaymentMethod: $method, + name: 'Konto', + description: null, + active: true, + configuration: ['iban' => 'DE123', 'account_owner' => 'Kasse', 'bic' => 'XY', 'evil' => 'x'], + ))->execute(); + + $this->assertTrue($response->success); + + $fresh = $method->fresh(); + $this->assertTrue($fresh->active); + $this->assertSame('DE123', $fresh->configuration['iban']); + $this->assertArrayNotHasKey('evil', $fresh->configuration); // unbekannte Keys verworfen + } + + public function test_event_assignment_copies_snapshot_and_preserves_overrides(): void + { + $this->availableMethod( + PaymentMethod::PAYMENT_ACCOUNT_TRANSACTION, + active: true, + config: ['iban' => 'DE-TENANT', 'account_owner' => 'Kasse'], + ); + + $event = $this->createEvent(); + + // 1. Zuweisung -> Snapshot der Tenant-Config landet im Pivot. + $this->runUpdateEvent($event, [PaymentMethod::PAYMENT_ACCOUNT_TRANSACTION]); + + $pivotConfig = $event->fresh()->paymentMethods()->first()->pivot->configuration; + $this->assertSame('DE-TENANT', $pivotConfig['iban']); + + // 2. Pro-Event-Override setzen. + $this->runUpdateEvent($event, [PaymentMethod::PAYMENT_ACCOUNT_TRANSACTION], [ + PaymentMethod::PAYMENT_ACCOUNT_TRANSACTION => ['iban' => 'DE-EVENT', 'account_owner' => 'Kasse'], + ]); + $this->assertSame('DE-EVENT', $event->fresh()->paymentMethods()->first()->pivot->configuration['iban']); + + // 3. Erneutes Speichern OHNE Override -> Override bleibt erhalten (kein Reset-Wipe). + $this->runUpdateEvent($event, [PaymentMethod::PAYMENT_ACCOUNT_TRANSACTION]); + $this->assertSame('DE-EVENT', $event->fresh()->paymentMethods()->first()->pivot->configuration['iban']); + } + + private function createEvent(): Event + { + return Event::create([ + 'tenant' => $this->tenant->slug, + 'name' => 'Event', + 'identifier' => 'evt-1', + 'location' => 'Ort', + 'postal_code' => '00000', + 'email' => 'e@example.com', + 'start_date' => '2026-08-01', + 'end_date' => '2026-08-05', + 'early_bird_end' => '2026-07-01', + 'registration_final_end' => '2026-07-20', + 'early_bird_end_amount_increase' => 0, + 'account_owner' => 'Owner', + 'account_iban' => 'DE00', + 'participation_fee_type' => 'FIXED', + 'pay_per_day' => false, + 'pay_direct' => false, + ]); + } + + /** + * @param array $slugs + * @param array> $configs + */ + private function runUpdateEvent(Event $event, array $slugs, array $configs = []): void + { + $request = new UpdateEventRequest( + $event, + $event->name, + $event->location, + $event->postal_code, + $event->email, + new \DateTime('2026-07-01'), + new \DateTime('2026-07-20'), + 16, + false, + false, + Amount::fromString('0'), + Amount::fromString('0'), + [], + [], + $slugs, + $configs, + ); + + $response = new UpdateEventCommand($request)->execute(); + $this->assertTrue($response->success, $response->message); + } +} diff --git a/tests/Unit/PaymentMethodOptionsTest.php b/tests/Unit/PaymentMethodOptionsTest.php new file mode 100644 index 0000000..5c95f00 --- /dev/null +++ b/tests/Unit/PaymentMethodOptionsTest.php @@ -0,0 +1,59 @@ +assertNotEmpty($options); + $this->assertSame('account_owner', $options[0]['name']); + } + + public function test_options_for_returns_empty_for_unknown_slug(): void + { + $this->assertSame([], PaymentMethod::optionsFor('DOES_NOT_EXIST')); + } + + public function test_required_option_keys_only_returns_required(): void + { + $keys = PaymentMethod::requiredOptionKeys(PaymentMethod::PAYMENT_ACCOUNT_TRANSACTION); + + $this->assertContains('account_owner', $keys); + $this->assertContains('iban', $keys); + $this->assertNotContains('bic', $keys); // bic ist optional + } + + public function test_sanitize_configuration_drops_unknown_keys(): void + { + $sanitized = PaymentMethod::sanitizeConfiguration(PaymentMethod::PAYMENT_ACCOUNT_TRANSACTION, [ + 'iban' => 'DE123', + 'account_owner' => 'Kasse', + 'evil' => 'x', + ]); + + $this->assertArrayHasKey('iban', $sanitized); + $this->assertArrayHasKey('account_owner', $sanitized); + $this->assertArrayNotHasKey('evil', $sanitized); + } + + public function test_is_configuration_complete_requires_all_required_options(): void + { + $slug = PaymentMethod::PAYMENT_ACCOUNT_TRANSACTION; + + $this->assertFalse(PaymentMethod::isConfigurationComplete($slug, [])); + $this->assertFalse(PaymentMethod::isConfigurationComplete($slug, ['iban' => 'DE123'])); + $this->assertFalse(PaymentMethod::isConfigurationComplete($slug, ['iban' => 'DE123', 'account_owner' => ''])); + $this->assertTrue(PaymentMethod::isConfigurationComplete($slug, ['iban' => 'DE123', 'account_owner' => 'Kasse'])); + } + + public function test_slug_without_options_is_always_complete(): void + { + $this->assertTrue(PaymentMethod::isConfigurationComplete(PaymentMethod::PAYMENT_NOT_DEFINED, [])); + } +}