schema([ Forms\Components\Section::make('General') ->schema([ Forms\Components\TextInput::make('name') ->autofocus() ->required() ->maxLength(255), Forms\Components\Textarea::make('description') ->label('Description'), ]), Forms\Components\Section::make('Configuration') ->schema([ Forms\Components\Select::make('category') ->localizeLabel() ->options(AdjustmentCategory::class) ->default(AdjustmentCategory::Tax) ->live() ->required(), Forms\Components\Select::make('type') ->localizeLabel() ->options(AdjustmentType::class) ->default(AdjustmentType::Sales) ->live() ->required(), Forms\Components\Checkbox::make('recoverable') ->label('Recoverable') ->default(false) ->helperText('When enabled, tax is tracked separately as claimable from the government. Non-recoverable taxes are treated as part of the expense.') ->visible(fn (Forms\Get $get) => AdjustmentCategory::parse($get('category'))->isTax() && AdjustmentType::parse($get('type'))->isPurchase()), ]) ->columns() ->visibleOn('create'), Forms\Components\Section::make('Adjustment Details') ->schema([ Forms\Components\Select::make('computation') ->localizeLabel() ->options(AdjustmentComputation::class) ->default(AdjustmentComputation::Percentage) ->live() ->required(), Forms\Components\TextInput::make('rate') ->localizeLabel() ->rate(static fn (Forms\Get $get) => $get('computation')) ->required(), Forms\Components\Select::make('scope') ->localizeLabel() ->options(AdjustmentScope::class), ]) ->columns(), Forms\Components\Section::make('Dates') ->schema([ Forms\Components\DateTimePicker::make('start_date'), Forms\Components\DateTimePicker::make('end_date') ->after('start_date'), ]) ->columns() ->visible(fn (Forms\Get $get) => AdjustmentCategory::parse($get('category'))->isDiscount()), ]); } public static function table(Table $table): Table { return $table ->columns([ Tables\Columns\TextColumn::make('name') ->label('Name') ->sortable(), Tables\Columns\TextColumn::make('category') ->searchable(), Tables\Columns\TextColumn::make('type') ->searchable(), Tables\Columns\TextColumn::make('status') ->badge(), Tables\Columns\TextColumn::make('rate') ->localizeLabel() ->rate(static fn (Adjustment $record) => $record->computation->value) ->searchable() ->sortable(), ]) ->filters([ // ]) ->actions([ Tables\Actions\ActionGroup::make([ Tables\Actions\EditAction::make(), Tables\Actions\Action::make('pause') ->label('Pause') ->icon('heroicon-m-pause') ->form([ Forms\Components\DateTimePicker::make('paused_until') ->label('Auto-resume Date') ->helperText('When should this adjustment automatically resume? Leave empty to keep paused indefinitely.') ->after('now'), Forms\Components\Textarea::make('status_reason') ->label('Reason for Pausing') ->maxLength(255), ]) ->visible(fn (Adjustment $record) => $record->canBePaused()) ->action(function (Adjustment $record, array $data) { $pausedUntil = $data['paused_until'] ?? null; $reason = $data['status_reason'] ?? null; $record->pause($reason, $pausedUntil); }), Tables\Actions\Action::make('resume') ->label('Resume') ->icon('heroicon-m-play') ->requiresConfirmation() ->visible(fn (Adjustment $record) => $record->canBeResumed()) ->action(fn (Adjustment $record) => $record->resume()), Tables\Actions\Action::make('archive') ->label('Archive') ->icon('heroicon-m-archive-box') ->color('danger') ->form([ Forms\Components\Textarea::make('status_reason') ->label('Reason for Archiving') ->maxLength(255), ]) ->visible(fn (Adjustment $record) => $record->canBeArchived()) ->action(function (Adjustment $record, array $data) { $reason = $data['status_reason'] ?? null; $record->archive($reason); }), ]), ]) ->bulkActions([ Tables\Actions\BulkActionGroup::make([ Tables\Actions\BulkAction::make('pause') ->label('Pause') ->icon('heroicon-m-pause') ->color('warning') ->form([ Forms\Components\DateTimePicker::make('paused_until') ->label('Auto-resume Date') ->helperText('When should these adjustments automatically resume? Leave empty to keep paused indefinitely.') ->after('now'), Forms\Components\Textarea::make('status_reason') ->label('Reason for Pausing') ->maxLength(255), ]) ->databaseTransaction() ->successNotificationTitle('Adjustments paused') ->failureNotificationTitle('Failed to pause adjustments') ->before(function (Collection $records, Tables\Actions\BulkAction $action) { $isInvalid = $records->contains(fn (Adjustment $record) => ! $record->canBePaused()); if ($isInvalid) { Notification::make() ->title('Pause failed') ->body('Only adjustments that are currently active can be paused. Please adjust your selection and try again.') ->persistent() ->danger() ->send(); $action->cancel(true); } }) ->deselectRecordsAfterCompletion() ->action(function (Collection $records, array $data) { $pausedUntil = $data['paused_until'] ?? null; $reason = $data['status_reason'] ?? null; $records->each(function (Adjustment $record) use ($reason, $pausedUntil) { $record->pause($reason, $pausedUntil); }); }), Tables\Actions\BulkAction::make('resume') ->label('Resume') ->icon('heroicon-m-play') ->color('success') ->databaseTransaction() ->successNotificationTitle('Adjustments resumed') ->failureNotificationTitle('Failed to resume adjustments') ->before(function (Collection $records, Tables\Actions\BulkAction $action) { $isInvalid = $records->contains(fn (Adjustment $record) => ! $record->canBeResumed()); if ($isInvalid) { Notification::make() ->title('Resume failed') ->body('Only adjustments that are currently paused can be resumed. Please adjust your selection and try again.') ->persistent() ->danger() ->send(); $action->cancel(true); } }) ->deselectRecordsAfterCompletion() ->action(function (Collection $records) { $records->each(function (Adjustment $record) { $record->resume(); }); }), Tables\Actions\BulkAction::make('archive') ->label('Archive') ->icon('heroicon-m-archive-box') ->color('danger') ->form([ Forms\Components\Textarea::make('status_reason') ->label('Reason for Archiving') ->maxLength(255), ]) ->databaseTransaction() ->successNotificationTitle('Adjustments archived') ->failureNotificationTitle('Failed to archive adjustments') ->before(function (Collection $records, Tables\Actions\BulkAction $action) { $isInvalid = $records->contains(fn (Adjustment $record) => ! $record->canBeArchived()); if ($isInvalid) { Notification::make() ->title('Archive failed') ->body('Only adjustments that are currently active or paused can be archived. Please adjust your selection and try again.') ->persistent() ->danger() ->send(); $action->cancel(true); } }) ->deselectRecordsAfterCompletion() ->action(function (Collection $records, array $data) { $reason = $data['status_reason'] ?? null; $records->each(function (Adjustment $record) use ($reason) { $record->archive($reason); }); }), ]), ]); } public static function getRelations(): array { return [ // ]; } public static function getPages(): array { return [ 'index' => Pages\ListAdjustments::route('/'), 'create' => Pages\CreateAdjustment::route('/create'), 'edit' => Pages\EditAdjustment::route('/{record}/edit'), ]; } }