Configurations for payment modules
This commit is contained in:
@@ -13,6 +13,7 @@ use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
* @property string $name
|
||||
* @property ?string $description
|
||||
* @property bool $active
|
||||
* @property ?array $configuration
|
||||
*/
|
||||
class AvailablePaymentMethod extends InstancedModel
|
||||
{
|
||||
@@ -24,10 +25,12 @@ class AvailablePaymentMethod extends InstancedModel
|
||||
'name',
|
||||
'description',
|
||||
'active',
|
||||
'configuration',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'active' => 'boolean',
|
||||
'configuration' => 'array',
|
||||
];
|
||||
|
||||
public function paymentMethod(): BelongsTo
|
||||
@@ -35,6 +38,14 @@ class AvailablePaymentMethod extends InstancedModel
|
||||
return $this->belongsTo(PaymentMethod::class, 'slug', 'slug');
|
||||
}
|
||||
|
||||
/**
|
||||
* Sind alle Pflicht-Optionen dieses Moduls (siehe PaymentMethod::OPTIONS) befüllt?
|
||||
*/
|
||||
public function isComplete(): bool
|
||||
{
|
||||
return PaymentMethod::isConfigurationComplete($this->slug, $this->configuration ?? []);
|
||||
}
|
||||
|
||||
public function events(): BelongsToMany
|
||||
{
|
||||
// Pivot verknüpft über den Slug -- Event::paymentMethods() greift daher automatisch nur
|
||||
|
||||
@@ -7,6 +7,7 @@ use App\Casts\AmountCast;
|
||||
use App\Enumerations\EatingHabit;
|
||||
use App\Enumerations\ParticipationFeeType;
|
||||
use App\RelationModels\EventParticipationFee;
|
||||
use App\RelationModels\EventPaymentMethods;
|
||||
use App\Resources\EventResource;
|
||||
use App\Scopes\CommonModel;
|
||||
use App\Scopes\InstancedModel;
|
||||
@@ -157,7 +158,10 @@ class Event extends InstancedModel
|
||||
// Pivot verknüpft über den Slug (payment_methods.slug), nicht über die numerische id
|
||||
// von available_payment_methods -- die tenant-spezifische Instanz wird dadurch implizit
|
||||
// über den globalen SiteScope von AvailablePaymentMethod (gefiltert auf app('tenant')) aufgelöst.
|
||||
return $this->belongsToMany(AvailablePaymentMethod::class, 'event_payment_methods', 'event_id', 'slug', 'id', 'slug')->withTimestamps();
|
||||
return $this->belongsToMany(AvailablePaymentMethod::class, 'event_payment_methods', 'event_id', 'slug', 'id', 'slug')
|
||||
->using(EventPaymentMethods::class)
|
||||
->withPivot('configuration')
|
||||
->withTimestamps();
|
||||
}
|
||||
|
||||
public function resetContributingLocalGroups() {
|
||||
|
||||
@@ -24,7 +24,84 @@ class PaymentMethod extends CommonModel
|
||||
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',
|
||||
];
|
||||
|
||||
/**
|
||||
* Options-Schema für einen Slug.
|
||||
*
|
||||
* @return array<int, array{name: string, label: string, type: string, required: bool}>
|
||||
*/
|
||||
public static function optionsFor(string $slug): array
|
||||
{
|
||||
return self::OPTIONS[$slug] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Namen aller Pflicht-Optionen eines Slugs.
|
||||
*
|
||||
* @return array<int, string>
|
||||
*/
|
||||
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)
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduziert eine Konfiguration auf die im Code definierten Options-Keys des Slugs.
|
||||
* Unbekannte Keys werden verworfen -- das Schema (self::OPTIONS) ist die Autorität.
|
||||
*
|
||||
* @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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prüft, ob alle Pflicht-Optionen eines Slugs in der Konfiguration befüllt (non-empty) sind.
|
||||
*
|
||||
* @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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user