schema([ Select::make('tenant_id') ->label('Tenant') ->relationship('tenant', 'name') ->searchable() ->preload() ->nullable(), Select::make('event_id') ->label('Event') ->relationship('event', 'name') ->searchable() ->preload() ->nullable(), Select::make('package_id') ->label('Package') ->relationship('package', 'name') ->searchable() ->preload() ->required(), TextInput::make('provider_id') ->label('Provider ID') ->required() ->maxLength(255), TextInput::make('price') ->label('Price') ->numeric() ->step(0.01) ->prefix('€') ->required(), Select::make('type') ->label('Type') ->options([ 'endcustomer_event' => 'Endcustomer Event', 'reseller_subscription' => 'Reseller Subscription', ]) ->required(), Textarea::make('metadata') ->label('Metadata') ->json() ->columnSpanFull(), Toggle::make('refunded') ->label('Refunded') ->default(false), ]) ->columns(2); } public static function table(Table $table): Table { return $table ->columns([ BadgeColumn::make('type') ->label('Type') ->color(fn (string $state): string => match($state) { 'endcustomer_event' => 'info', 'reseller_subscription' => 'success', default => 'gray', }), TextColumn::make('tenant.name') ->label('Tenant') ->searchable() ->sortable() ->toggleable(isToggledHiddenByDefault: true), TextColumn::make('event.name') ->label('Event') ->searchable() ->toggleable(isToggledHiddenByDefault: true), TextColumn::make('package.name') ->label('Package') ->badge() ->color('success'), TextColumn::make('price') ->label('Price') ->money('EUR') ->sortable(), TextColumn::make('purchased_at') ->dateTime() ->sortable(), BadgeColumn::make('refunded') ->label('Status') ->color(fn (bool $state): string => $state ? 'danger' : 'success'), TextColumn::make('provider_id') ->copyable() ->toggleable(), ]) ->filters([ SelectFilter::make('type') ->options([ 'endcustomer_event' => 'Endcustomer Event', 'reseller_subscription' => 'Reseller Subscription', ]), Filter::make('purchased_at') ->form([ DateTimePicker::make('started_from'), DateTimePicker::make('ended_before'), ]) ->query(function (Builder $query, array $data): Builder { return $query ->when( $data['started_from'], fn (Builder $query, $date): Builder => $query->whereDate('purchased_at', '>=', $date), ) ->when( $data['ended_before'], fn (Builder $query, $date): Builder => $query->whereDate('purchased_at', '<=', $date), ); }), SelectFilter::make('tenant_id') ->label('Tenant') ->relationship('tenant', 'name') ->searchable(), ]) ->actions([ ViewAction::make(), EditAction::make(), Action::make('refund') ->label('Refund') ->color('danger') ->icon('heroicon-o-arrow-uturn-left') ->requiresConfirmation() ->visible(fn (PackagePurchase $record): bool => !$record->refunded) ->action(function (PackagePurchase $record) { $record->update(['refunded' => true]); // TODO: Call Stripe/PayPal API for actual refund Log::info('Refund processed for purchase ID: ' . $record->id); }), ]) ->bulkActions([ BulkActionGroup::make([ DeleteBulkAction::make(), ]), ]) ->emptyStateHeading('No Purchases Found') ->emptyStateDescription('Create your first purchase.'); } public static function getPages(): array { return [ 'index' => Pages\ListPurchases::route('/'), 'create' => Pages\CreatePurchase::route('/create'), 'view' => Pages\ViewPurchase::route('/{record}'), 'edit' => Pages\EditPurchase::route('/{record}/edit'), ]; } public static function getRelations(): array { return [ // Add RelationManagers if needed ]; } }