count(); return $overdue > 0 ? (string) $overdue : null; } public static function getNavigationBadgeColor(): ?string { return 'danger'; } public static function form(Schema $schema): Schema { return $schema->components([ Schemas\Components\Section::make('Companie & plan') ->columns(2) ->schema([ Forms\Components\Select::make('company_id') ->label('Companie') ->options(fn () => Company::orderBy('name')->pluck('name', 'id')) ->required()->searchable()->live(), Forms\Components\Select::make('plan_id') ->label('Plan') ->options(fn () => Plan::pluck('name', 'id')) ->required()->searchable()->live() ->afterStateUpdated(function ($state, Set $set, Get $get) { if (! $state) return; $plan = Plan::find($state); if (! $plan) return; $period = $get('period') ?? 'monthly'; $set('amount', $period === 'yearly' ? $plan->price_yearly : $plan->price_monthly); $set('currency', $plan->currency); }), Forms\Components\Select::make('period') ->options(Subscription::PERIODS)->default('monthly')->required()->live() ->afterStateUpdated(function ($state, Set $set, Get $get) { $plan = Plan::find($get('plan_id')); if (! $plan) return; $set('amount', $state === 'yearly' ? $plan->price_yearly : $plan->price_monthly); // Auto-fill period_end based on period $start = $get('period_start') ?? now()->toDateString(); $end = $state === 'yearly' ? \Carbon\Carbon::parse($start)->addYear()->toDateString() : \Carbon\Carbon::parse($start)->addMonth()->toDateString(); $set('period_end', $end); }), Forms\Components\Select::make('status') ->options(Subscription::STATUSES)->default('pending')->required(), ]), Schemas\Components\Section::make('Sumă') ->columns(3) ->schema([ Forms\Components\TextInput::make('amount')->numeric()->required()->suffix(fn (Get $get) => $get('currency') ?? 'MDL'), Forms\Components\Select::make('currency')->options(['MDL' => 'MDL', 'EUR' => 'EUR', 'USD' => 'USD'])->default('MDL'), Forms\Components\Select::make('payment_method') ->options(Subscription::PAYMENT_METHODS), ]), Schemas\Components\Section::make('Perioadă') ->columns(3) ->schema([ Forms\Components\DatePicker::make('period_start')->required()->default(today()), Forms\Components\DatePicker::make('period_end')->required(), Forms\Components\DateTimePicker::make('due_at')->label('Scadent la'), Forms\Components\DateTimePicker::make('paid_at')->label('Plătit la'), ]), Schemas\Components\Section::make('Detalii') ->columns(2) ->schema([ Forms\Components\TextInput::make('invoice_number')->label('Nr. factură')->placeholder('auto-generat')->maxLength(30), Forms\Components\TextInput::make('reference')->label('Referință (Stripe id, transfer)')->maxLength(100), Forms\Components\Textarea::make('notes')->columnSpanFull()->rows(2), ]), ]); } public static function table(Table $table): Table { return $table ->columns([ Tables\Columns\TextColumn::make('invoice_number') ->label('Factură') ->placeholder(fn ($r) => '—') ->copyable() ->searchable(), Tables\Columns\TextColumn::make('company.name') ->label('Companie') ->searchable() ->url(fn ($r) => \App\Filament\Central\Resources\CompanyResource::getUrl('view', ['record' => $r->company_id])), Tables\Columns\TextColumn::make('plan.name')->label('Plan')->placeholder('—'), Tables\Columns\TextColumn::make('period') ->formatStateUsing(fn ($s) => Subscription::PERIODS[$s] ?? $s) ->badge(), Tables\Columns\TextColumn::make('amount') ->money(fn ($r) => $r->currency) ->sortable() ->weight('bold'), Tables\Columns\TextColumn::make('status') ->badge() ->formatStateUsing(fn ($s) => Subscription::STATUSES[$s] ?? $s) ->color(fn ($s) => match ($s) { 'paid' => 'success', 'overdue' => 'danger', 'pending' => 'warning', 'cancelled', 'refunded' => 'gray', default => 'primary', }), Tables\Columns\TextColumn::make('period_end')->label('Până la')->date(), Tables\Columns\TextColumn::make('paid_at')->label('Plătit')->date()->placeholder('—'), ]) ->filters([ Tables\Filters\SelectFilter::make('status')->options(Subscription::STATUSES), Tables\Filters\SelectFilter::make('period')->options(Subscription::PERIODS), ]) ->actions([ Actions\Action::make('mark_paid') ->label('Marchează plătit') ->icon('heroicon-m-check-circle') ->color('success') ->visible(fn ($r) => $r->status !== 'paid') ->requiresConfirmation() ->action(function (Subscription $r) { $r->update(['status' => 'paid', 'paid_at' => now()]); // Auto-extend company subscription $r->company->update([ 'status' => 'active', 'active_until' => $r->period_end, ]); Notification::make()->title('Plată confirmată. Abonament extins până la ' . $r->period_end->format('d.m.Y'))->success()->send(); }), Actions\EditAction::make(), Actions\DeleteAction::make(), ]) ->emptyStateHeading('Nicio factură generată') ->emptyStateDescription('Crează manual prima factură sau folosește butonul „Generează factură" din pagina Companiei.') ->defaultSort('created_at', 'desc'); } public static function getPages(): array { return [ 'index' => Pages\ListSubscriptions::route('/'), 'create' => Pages\CreateSubscription::route('/create'), 'edit' => Pages\EditSubscription::route('/{record}/edit'), ]; } }