ifnex/04_Laravel/app/Filament/Resources/UserResource.php
Kazem Alghasi 93ebbb1fc8 feat(finance): implement multi-currency credit tracking and dashboard widgets
Integrate multi-currency debt visibility across the platform by adding
support for foreign currency credits in the user profile shortcode,
improving the admin dashboard with unsettled credits widgets, and
enhancing the Filament admin panel with navigation badges and relation
managers.

- Add multi-currency debt table to WordPress user profile shortcode
- Implement `UnsettledCreditsWidget` for Filament dashboard
- Add navigation badge to `CustomerCreditResource` for open credits
- Add `CreditsRelationManager` to `UserResource`
- Update `CustomerOrderController` API to include `foreign_credits`
- Add concurrency check in `CustomerCreditService` during settlement
2026-10-04 01:01:20 +03:30

273 lines
11 KiB
PHP

<?php
namespace App\Filament\Resources;
use App\Filament\Resources\UserResource\Pages;
use App\Filament\Resources\UserResource\RelationManagers;
use App\Models\User;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
use Filament\Tables\Actions\Action;
use Filament\Notifications\Notification;
use Illuminate\Support\Facades\Hash;
use Spatie\Permission\Models\Role;
use Illuminate\Support\Facades\Auth;
class UserResource extends Resource
{
protected static ?string $model = User::class;
protected static ?string $navigationIcon = 'heroicon-o-users';
protected static ?string $navigationLabel = 'کاربران';
protected static ?string $modelLabel = 'کاربر';
protected static ?string $pluralModelLabel = 'کاربران';
protected static ?string $navigationGroup = 'تنظیمات';
protected static ?int $navigationSort = 1;
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\Section::make('اطلاعات اصلی')
->schema([
Forms\Components\TextInput::make('name')
->label('نام و نام خانوادگی')
->required()
->maxLength(255),
Forms\Components\TextInput::make('email')
->label('ایمیل')
->email()
->required()
->unique(ignoreRecord: true)
->maxLength(255),
Forms\Components\TextInput::make('phone')
->label('شماره موبایل')
->tel()
->maxLength(20),
Forms\Components\TextInput::make('password')
->label('رمز عبور')
->password()
->revealable()
->required(fn (string $operation): bool => $operation === 'create')
->dehydrated(fn ($state): bool => filled($state))
->dehydrateStateUsing(fn ($state): string => Hash::make($state))
->helperText('برای تغییر رمز عبور، رمز جدید را وارد کنید. در غیر این صورت خالی بگذارید.'),
])->columns(2),
Forms\Components\Section::make('نقش و دسترسی‌ها')
->schema([
Forms\Components\Select::make('roles')
->label('نقش‌های کاربر')
->relationship('roles', 'name')
->multiple()
->preload()
->searchable()
->required()
->minItems(1)
->helperText('حداقل یک نقش باید انتخاب شود'),
Forms\Components\Toggle::make('is_active')
->label('وضعیت فعال')
->default(true)
->helperText('کاربران غیرفعال نمی‌توانند وارد سیستم شوند'),
]),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('id')
->label('شناسه')
->sortable()
->searchable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('name')
->label('نام')
->searchable()
->sortable(),
Tables\Columns\TextColumn::make('email')
->label('ایمیل')
->searchable()
->sortable()
->copyable()
->copyMessage('ایمیل کپی شد')
->copyMessageDuration(1500),
Tables\Columns\TextColumn::make('phone')
->label('موبایل')
->searchable()
->toggleable(),
Tables\Columns\TextColumn::make('roles.name')
->label('نقش‌ها')
->badge()
->color(fn (string $state): string => match ($state) {
'super_admin' => 'danger',
'admin' => 'warning',
'staff' => 'info',
'customer' => 'success',
default => 'gray',
})
->separator('، '),
Tables\Columns\IconColumn::make('is_active')
->label('فعال')
->boolean()
->sortable()
->trueIcon('heroicon-o-check-circle')
->falseIcon('heroicon-o-x-circle')
->trueColor('success')
->falseColor('danger'),
Tables\Columns\TextColumn::make('created_at')
->label('تاریخ عضویت')
->dateTime('Y/m/d')
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
Tables\Filters\SelectFilter::make('role')
->label('نقش')
->options([
'super_admin' => 'مدیر ارشد',
'admin' => 'مدیر',
'staff' => 'کارمند',
'customer' => 'مشتری',
])
->query(function ($query, array $data) {
return $query->when($data['value'], function ($query, $role) {
return $query->role($role);
});
}),
Tables\Filters\TernaryFilter::make('is_active')
->label('وضعیت فعال'),
])
->actions([
Tables\Actions\EditAction::make()
->label('ویرایش'),
Action::make('toggleActive')
->label(fn ($record) => $record->is_active ? 'غیرفعال کردن' : 'فعال کردن')
->icon(fn ($record) => $record->is_active ? 'heroicon-o-x-circle' : 'heroicon-o-check-circle')
->color(fn ($record) => $record->is_active ? 'danger' : 'success')
->requiresConfirmation()
->action(function (User $record) {
$record->update(['is_active' => !$record->is_active]);
Notification::make()
->title($record->is_active ? 'کاربر فعال شد' : 'کاربر غیرفعال شد')
->success()
->send();
}),
Action::make('resetPassword')
->label('بازنشانی رمز')
->icon('heroicon-o-key')
->color('warning')
->form([
Forms\Components\TextInput::make('password')
->label('رمز عبور جدید')
->password()
->revealable()
->required()
->minLength(8),
])
->requiresConfirmation()
->action(function (User $record, array $data) {
$record->update([
'password' => Hash::make($data['password']),
]);
Notification::make()
->title('رمز عبور با موفقیت بازنشانی شد')
->success()
->send();
}),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make()
->label('حذف انتخاب‌شده‌ها'),
]),
])
->defaultSort('created_at', 'desc');
}
public static function getRelations(): array
{
return [
RelationManagers\CreditsRelationManager::class,
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListUsers::route('/'),
'create' => Pages\CreateUser::route('/create'),
'edit' => Pages\EditUser::route('/{record}/edit'),
];
}
// ─── Access Control ───
protected static function getCurrentUser(): ?\App\Models\User
{
$user = Auth::user();
return $user instanceof \App\Models\User ? $user : null;
}
// فقط super_admin و admin می‌توانند کاربران را ببینند
public static function canViewAny(): bool
{
$user = static::getCurrentUser();
return $user !== null && $user->hasAnyRole(['super_admin', 'admin']);
}
// فقط super_admin می‌تواند کاربر جدید بسازد
public static function canCreate(): bool
{
$user = static::getCurrentUser();
return $user !== null && $user->hasRole('super_admin');
}
// super_admin و admin می‌توانند ویرایش کنند
public static function canEdit($record): bool
{
$user = static::getCurrentUser();
if ($user === null) return false;
// admin نمی‌تواند super_admin را ویرایش کند
if ($user->hasRole('admin') && $record->hasRole('super_admin')) {
return false;
}
return $user->hasAnyRole(['super_admin', 'admin']);
}
// فقط super_admin می‌تواند کاربر حذف کند
public static function canDelete($record): bool
{
$user = static::getCurrentUser();
if ($user === null) return false;
// super_admin نمی‌تواند خودش را حذف کند
if ($record->id === $user->id) {
return false;
}
return $user->hasRole('super_admin');
}
}