ifnex/04_Laravel/app/Filament/Resources/DiscountCodeResource.php
Kazem Alghasi e1c4385a9c feat(finance): implement Filament admin panel and expand wallet/discount features
Implement a comprehensive financial management suite within the Filament
admin panel, including new resources for payments and discount codes,
along with a financial dashboard.

- feat(ui): add Filament Dashboard with finance overview and transaction
  widgets
- feat(ui): implement PaymentResource for monitoring gateway transactions
- feat(ui): complete DiscountCodeResource with full CRUD and filtering
- feat(wallet): add automatic wallet creation on balance retrieval
- fix(wallet): resolve null handling in isFrozen() and balance viewing
- fix(db): correct enum type from 'percent' to 'percentage' in
  discount_codes migration
- fix(api): update pricing calculation endpoint to /api/v1/calculate
- test: add 21 new feature and service tests covering wallet, payment,
  and discount logic
- chore: remove obsolete PaymentGatewayService and update project status
2026-08-08 03:15:51 +03:30

192 lines
7.6 KiB
PHP

<?php
namespace App\Filament\Resources;
use App\Filament\Resources\DiscountCodeResource\Pages;
use App\Models\DiscountCode;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
class DiscountCodeResource extends Resource
{
protected static ?string $model = DiscountCode::class;
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
protected static ?string $navigationLabel = 'کدهای تخفیف';
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('code')
->required()
->unique(ignoreRecord: true)
->maxLength(50)
->label('کد تخفیف')
->columnSpanFull(),
Forms\Components\Select::make('type')
->options([
'percentage' => 'درصدی',
'fixed' => 'مبلغ ثابت',
])
->required()
->label('نوع تخفیف')
->reactive()
->columnSpan(1),
Forms\Components\TextInput::make('value')
->required()
->numeric()
->label(fn ($get) => $get('type') === 'percentage' ? 'درصد تخفیف' : 'مبلغ تخفیف (ریال)')
->suffix(fn ($get) => $get('type') === 'percentage' ? '%' : 'ریال')
->maxLength(13)
->columnSpan(1),
Forms\Components\Toggle::make('is_active')
->label('فعال')
->default(true)
->columnSpanFull(),
Forms\Components\TextInput::make('min_order_amount')
->numeric()
->label('حداقل مبلغ سفارش (ریال)')
->suffix('ریال')
->default(0)
->columnSpan(1),
Forms\Components\TextInput::make('usage_limit')
->numeric()
->label('محدودیت استفاده')
->suffix('بار')
->nullable()
->columnSpan(1),
Forms\Components\TextInput::make('used_count')
->numeric()
->label('تعداد استفاده شده')
->default(0)
->disabled()
->columnSpan(1),
Forms\Components\DateTimePicker::make('expires_at')
->label('تاریخ انقضا')
->nullable()
->displayFormat('Y/m/d H:i')
->columnSpanFull(),
])
->columns(2),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('code')
->label('کد')
->searchable()
->sortable()
->copyable()
->copyMessage('کد کپی شد!')
->fontFamily('mono'),
Tables\Columns\BadgeColumn::make('type')
->label('نوع')
->getStateUsing(fn ($record) => $record->type === 'percentage' ? 'درصدی' : 'ثابت')
->colors([
'success' => 'percentage',
'info' => 'fixed',
]),
Tables\Columns\TextColumn::make('value')
->label('مقدار')
->getStateUsing(fn ($record) => $record->type === 'percentage' ? $record->value . '%' : number_format($record->value) . ' ریال')
->sortable(),
Tables\Columns\TextColumn::make('min_order_amount')
->label('حداقل سفارش')
->getStateUsing(fn ($record) => $record->min_order_amount > 0 ? number_format($record->min_order_amount) . ' ریال' : 'بدون محدودیت')
->sortable(),
Tables\Columns\TextColumn::make('usage_limit')
->label('محدودیت')
->getStateUsing(fn ($record) => $record->usage_limit ? $record->usage_limit . ' بار' : 'نامحدود')
->sortable(),
Tables\Columns\TextColumn::make('used_count')
->label('استفاده شده')
->getStateUsing(fn ($record) => $record->usage_limit ? "{$record->used_count} / {$record->usage_limit}" : "{$record->used_count} / ∞")
->sortable(),
Tables\Columns\IconColumn::make('is_active')
->label('فعال')
->boolean()
->trueIcon('heroicon-o-check-circle')
->falseIcon('heroicon-o-x-circle')
->trueColor('success')
->falseColor('danger'),
Tables\Columns\TextColumn::make('expires_at')
->label('انقضا')
->dateTime('Y/m/d H:i', 'Asia/Tehran')
->sortable()
->color(fn ($record) => $record->expires_at?->isPast() ? 'danger' : null),
Tables\Columns\TextColumn::make('created_at')
->label('تاریخ ایجاد')
->dateTime('Y/m/d H:i', 'Asia/Tehran')
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
Tables\Filters\TernaryFilter::make('is_active')
->label('وضعیت فعال'),
Tables\Filters\SelectFilter::make('type')
->label('نوع تخفیف')
->options([
'percentage' => 'درصدی',
'fixed' => 'مبلغ ثابت',
]),
Tables\Filters\Filter::make('expired')
->label('منقضی شده')
->query(fn (Builder $query): Builder => $query->where('expires_at', '<', now())),
])
->actions([
Tables\Actions\EditAction::make(),
Tables\Actions\DeleteAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
]),
]);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => Pages\ListDiscountCodes::route('/'),
'create' => Pages\CreateDiscountCode::route('/create'),
'edit' => Pages\EditDiscountCode::route('/{record}/edit'),
];
}
}