components([ Select::make('tenant_id') ->label('Tenant') ->relationship('tenant', 'name') ->searchable() ->preload() ->required(), Select::make('package_id') ->label('Paket') ->options([ 'starter_pack' => 'Starter Pack (5 Events)', 'pro_pack' => 'Pro Pack (20 Events)', 'lifetime_unlimited' => 'Lifetime Unlimited', 'monthly_pro' => 'Pro Subscription', 'monthly_agency' => 'Agency Subscription', ]) ->required(), TextInput::make('price') ->label('Preis') ->numeric() ->step(0.01) ->prefix('€') ->required(), Select::make('platform') ->label('Plattform') ->options([ 'ios' => 'iOS', 'android' => 'Android', 'web' => 'Web', 'manual' => 'Manuell', ]) ->required(), TextInput::make('transaction_id') ->label('Transaktions-ID') ->maxLength(255), Textarea::make('reason') ->label('Beschreibung') ->maxLength(65535) ->columnSpanFull(), ]) ->columns(2); } public static function table(Table $table): Table { return $table ->columns([ TextColumn::make('tenant.name') ->label('Tenant') ->searchable() ->sortable(), TextColumn::make('package_id') ->label('Paket') ->badge() ->color(fn (string $state): string => match ($state) { 'starter_pack' => 'info', 'pro_pack' => 'success', 'lifetime_unlimited' => 'danger', 'monthly_pro' => 'warning', default => 'gray', }), TextColumn::make('price') ->label('Preis') ->money('EUR') ->sortable(), TextColumn::make('platform') ->badge() ->color(fn (string $state): string => match ($state) { 'ios' => 'info', 'android' => 'success', 'web' => 'warning', 'manual' => 'gray', }), TextColumn::make('purchased_at') ->dateTime() ->sortable(), TextColumn::make('transaction_id') ->copyable() ->toggleable(), ]) ->filters([ Filter::make('created_at') ->form([ DatePicker::make('started_from'), DatePicker::make('ended_before'), ]) ->query(function (Builder $query, array $data): Builder { return $query ->when( $data['started_from'], fn (Builder $query, $date): Builder => $query->whereDate('created_at', '>=', $date), ) ->when( $data['ended_before'], fn (Builder $query, $date): Builder => $query->whereDate('created_at', '<=', $date), ); }), SelectFilter::make('platform') ->options([ 'ios' => 'iOS', 'android' => 'Android', 'web' => 'Web', 'manual' => 'Manuell', ]), SelectFilter::make('package_id') ->options([ 'starter_pack' => 'Starter Pack', 'pro_pack' => 'Pro Pack', 'lifetime_unlimited' => 'Lifetime', 'monthly_pro' => 'Pro Subscription', 'monthly_agency' => 'Agency Subscription', ]), TernaryFilter::make('successful') ->label('Erfolgreich') ->trueLabel('Ja') ->falseLabel('Nein') ->placeholder('Alle') ->query(fn (Builder $query): Builder => $query->whereNotNull('transaction_id')), ]) ->actions([ ViewAction::make(), Action::make('refund') ->label('Rückerstattung') ->color('danger') ->icon('heroicon-o-arrow-uturn-left') ->requiresConfirmation() ->visible(fn (EventPurchase $record): bool => $record->transaction_id && is_null($record->refunded_at)) ->action(function (EventPurchase $record) { $record->update(['refunded_at' => now()]); Log::info('Refund processed for purchase ID: '.$record->id); }), ]) ->bulkActions([ BulkActionGroup::make([ DeleteBulkAction::make(), ExportBulkAction::make() ->label('Export CSV') ->exporter(EventPurchaseExporter::class), ]), ]) ->emptyStateHeading('Keine Käufe gefunden') ->emptyStateDescription('Erstelle den ersten Kauf oder überprüfe die Filter.'); } public static function getPages(): array { return [ 'index' => Pages\ListEventPurchases::route('/'), 'create' => Pages\CreateEventPurchase::route('/create'), 'view' => Pages\ViewEventPurchase::route('/{record}'), 'edit' => Pages\EditEventPurchase::route('/{record}/edit'), ]; } }