Configurations for payment modules

This commit is contained in:
2026-07-29 15:49:26 +02:00
parent 8d6a4041c1
commit 78f4d813f9
19 changed files with 584 additions and 51 deletions
+1 -1
View File
@@ -39,7 +39,7 @@ class AvailablePaymentMethod extends InstancedModel
}
/**
* Sind alle Pflicht-Optionen dieses Moduls (siehe PaymentMethod::OPTIONS) befüllt?
* Sind alle Pflicht-Optionen dieses Moduls (siehe Options-Schema des Zahlungsmoduls) befüllt?
*/
public function isComplete(): bool
{
+26 -46
View File
@@ -2,12 +2,17 @@
namespace App\Models;
use App\EventPaymentModules\EventPaymentModuleRegistry;
use App\Scopes\CommonModel;
use Illuminate\Database\Eloquent\Concerns\HasUuids;
/**
* @property string $id
* @property string $slug
*
* Hinweis: Das Verhalten je Zahlungsart (Options-Schema, Defaults, Zahlung, Rechnung) liegt in den
* Zahlungsmodulen unter {@see \App\EventPaymentModules}. Dieses Model bleibt eine dünne Fassade, damit
* bestehende Aufrufstellen (PaymentMethod::optionsFor/... ) unverändert weiterlaufen.
*/
class PaymentMethod extends CommonModel
{
@@ -19,33 +24,25 @@ class PaymentMethod extends CommonModel
public const string PAYMENT_ACCOUNT_TRANSACTION = 'PAYMENT_ACCOUNT_TRANSACTION';
public const string PAYMENT_NOT_DEFINED = 'PAYMENT_NOT_DEFINED';
public const array DEFAULTS = [
self::PAYMENT_ACCOUNT_TRANSACTION => ['name' => 'Überweisung auf Veranstaltungskonto', 'description' => null],
self::PAYMENT_NOT_DEFINED => ['name' => 'Sonstiges (Barzahlung, Zahlung vor Ort)', 'description' => null],
];
/**
* Options-Schema je Zahlungsmodul. Definiert im Code (nicht in der DB), damit es
* nicht mit dem Modul-Code auseinanderdriftet. In der DB stehen nur die Werte
* (configuration-JSON auf available_payment_methods bzw. event_payment_methods).
*
* Jede Option: ['name' => string, 'label' => string, 'type' => string, 'required' => bool]
*
* @var array<string, array<int, array{name: string, label: string, type: string, required: bool}>>
*/
public const array OPTIONS = [
self::PAYMENT_ACCOUNT_TRANSACTION => [
['name' => 'account_owner', 'label' => 'Kontoinhaber', 'type' => 'string', 'required' => true],
['name' => 'iban', 'label' => 'IBAN', 'type' => 'string', 'required' => true],
['name' => 'bic', 'label' => 'BIC', 'type' => 'string', 'required' => false],
],
self::PAYMENT_NOT_DEFINED => [],
];
protected $fillable = [
'slug',
];
/**
* Standard-Werte (name/description) je Slug -- aus den Zahlungsmodulen aufgebaut.
*
* @return array<string, array{name: string, description: ?string}>
*/
public static function defaults(): array
{
$defaults = [];
foreach (EventPaymentModuleRegistry::all() as $slug => $module) {
$defaults[$slug] = ['name' => $module->defaultName(), 'description' => $module->defaultDescription()];
}
return $defaults;
}
/**
* Options-Schema für einen Slug.
*
@@ -53,7 +50,7 @@ class PaymentMethod extends CommonModel
*/
public static function optionsFor(string $slug): array
{
return self::OPTIONS[$slug] ?? [];
return EventPaymentModuleRegistry::forSlug($slug)?->getOptions() ?? [];
}
/**
@@ -63,45 +60,28 @@ class PaymentMethod extends CommonModel
*/
public static function requiredOptionKeys(string $slug): array
{
return array_values(array_map(
static fn (array $option) => $option['name'],
array_filter(self::optionsFor($slug), static fn (array $option) => $option['required'] ?? false)
));
return EventPaymentModuleRegistry::forSlug($slug)?->requiredOptionKeys() ?? [];
}
/**
* Reduziert eine Konfiguration auf die im Code definierten Options-Keys des Slugs.
* Unbekannte Keys werden verworfen -- das Schema (self::OPTIONS) ist die Autorität.
* Reduziert eine Konfiguration auf die im Schema definierten Options-Keys des Slugs.
*
* @param array<string, mixed> $config
* @return array<string, mixed>
*/
public static function sanitizeConfiguration(string $slug, array $config): array
{
$result = [];
foreach (self::optionsFor($slug) as $option) {
if (array_key_exists($option['name'], $config)) {
$result[$option['name']] = $config[$option['name']];
}
}
return $result;
return EventPaymentModuleRegistry::forSlug($slug)?->sanitizeConfiguration($config) ?? [];
}
/**
* Prüft, ob alle Pflicht-Optionen eines Slugs in der Konfiguration befüllt (non-empty) sind.
* Unbekannte Slugs (kein Modul) gelten als vollständig -- kein Modul, keine Pflichtfelder.
*
* @param array<string, mixed> $config
*/
public static function isConfigurationComplete(string $slug, array $config): bool
{
foreach (self::requiredOptionKeys($slug) as $key) {
$value = $config[$key] ?? null;
if ($value === null || $value === '' || $value === []) {
return false;
}
}
return true;
return EventPaymentModuleRegistry::forSlug($slug)?->isConfigurationComplete($config) ?? true;
}
}